Behavioral results. Let’s look at how participants performed in the task
First, let’s load the data. These data import functions are defined in dataProcessing.R where I convert the raw data into a usuable dataframe.
Training Phase
Before the main bandit task, participants performed a training phase where they were required to match a target stimuli until a learning criterion was met (at least 32 trials and a run of 9 out of 10 correct). The task used the same stimuli and inputs as the main bandit task, and was used to familiarize participants and have them achieve a similar level of fluency with both spatial and conceptual domains. Let’s first look at some of the results.
Participants had a lower accuracy on the conceptual training (\(t(128)=7.5\), \(p<.001\), \(d=0.8\), \(BF>100\)) and required more trials to reach the training criterion (\(Z=-4.1\), \(p<.001\), \(r=-.40\), \(BF>100\)), which is to be expected since it is intuitively more difficult.
#Overall Correct choices
dat <- ddply(df, ~id+context, plyr::summarize, trajCorrect = mean(trajCorrect), trajAvgSteps = mean(trajAvgSteps))
trajp1a<- ggplot(dat, aes(x = context, y = trajCorrect, color = context))+
geom_line(aes(group=id),color = 'black', alpha = 0.1)+
geom_boxplot(outlier.shape = NA, fill=NA, color = 'black', width = 0.1)+
geom_quasirandom(alpha = 0.7)+
stat_summary(fun.y=mean, geom='point', shape=23, color = 'black', size =3)+
ylab('P(correct)')+
xlab('')+
scale_color_brewer(palette = "Dark2", name = "") +
theme(legend.position='none')
trajp1a

#Trials until complete
dat <- ddply(trajDF, ~id+context, plyr::summarize, trajTrials = max(trial))
#ttestPretty(subset(dat, context == 'Spatial')$trajTrials, subset(dat, context == 'Conceptual')$trajTrials, paired=T) #Data doesn't look very normal
#ranktestPretty(subset(dat, context == 'Spatial')$trajTrials, subset(dat, context == 'Conceptual')$trajTrials, paired=T) #Is there a meaninful difference in the number of trials needed to finish the training phase? #Note sometimes Bayes Factors display as NA when they are very large
trajComplete <- ggplot(dat, aes(x = context, y = trajTrials, color = context))+
geom_line(aes(group=id),color = 'black', alpha = 0.1)+
geom_quasirandom( alpha = 0.6)+
geom_boxplot(color='black', fill= NA, width =.2, outlier.shape = NA)+
stat_summary(fun.y = mean, geom='point', shape = 23,size=3, color = 'black')+
geom_hline(yintercept = 32, linetype = 'dashed')+
scale_color_brewer(palette = "Dark2", name = "") +
ylab('Trials Until Complete')+
xlab('')+
#coord_cartesian(ylim=c(30,128), )+
scale_y_continuous(breaks=c(32,64, 96, 128), limits = c(32,128))+
theme(legend.position = 'none')
trajComplete

We can also look at the magnitude of errors vs. the frequenvy of occurence, which gives us a nice Shepard (1987) style generalization gradient.
#Magnitude of error vs. frequency
gradientDF <- ddply(trajDF, ~context+manhattanError,plyr::summarize, counts = table(manhattanError))
#Normalize into a percentage
gradientDF[gradientDF$context == 'Conceptual','P'] <- gradientDF[gradientDF$context == 'Conceptual','counts']/sum(gradientDF[gradientDF$context == 'Conceptual','counts'])
gradientDF[gradientDF$context == 'Spatial','P'] <- gradientDF[gradientDF$context == 'Spatial','counts']/sum(gradientDF[gradientDF$context == 'Spatial','counts'])
pError<- ggplot(gradientDF, aes(x = manhattanError, y = P, color = context, shape = context))+
geom_line()+
geom_point()+
coord_cartesian(xlim=c(0,5))+
ylab('P(error)')+
xlab('Magnitude of Error (Manhattan distance)')+
scale_color_brewer(palette = "Dark2", name = "Task")+
scale_shape_manual( values = c(16,15),name = "Task")+
theme(legend.position=c(1,1), legend.justification = c(1,1))
pError

How did accuracy differ for the different options?
spatialCounts <- ddply(subset(trajDF, context == 'Spatial'), .(x, y), plyr::summarize, correct = sum(trajCorrect)/length(trajCorrect))
names(spatialCounts) <- c("X", "Y", "Accuracy")
spatialCounts$task <- 'Spatial'
conceptCounts <- ddply(subset(df, context == 'Conceptual'), .(x, y), plyr::summarize, correct = sum(trajCorrect)/length(trajCorrect))
names(conceptCounts) <- c("X", "Y", "Accuracy")
conceptCounts$task <- 'Conceptual'
trainingAccuracyDF <-rbind(spatialCounts, conceptCounts)
trajheatmap<- ggplot(trainingAccuracyDF, aes(x=X, y = Y, fill=Accuracy)) +
geom_tile()+
scale_fill_distiller(palette = "Spectral", name = 'P(correct)',limits = c(0,1),labels = scales::percent_format(accuracy = 1))+
theme_classic() +
facet_grid(~task)+
coord_equal() +
theme(strip.background=element_blank(), legend.key=element_rect(color=NA), axis.line=element_blank(),axis.text.x=element_blank(),
axis.text.y=element_blank(),axis.ticks=element_blank(), panel.background=element_blank(),panel.border=element_blank(),panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),plot.background=element_blank())+
labs(x = '', y = '')
trajheatmap

Performance
Now let’s finally look at performance on the bandit task.
#Construct plotting dataframes
meanDF <- ddply(df, .(id, context, environment, contextOrder), plyr::summarize, meanScore = mean(z))
conceptualScores <- subset(meanDF, context == "Conceptual")
spatialScores <- subset(meanDF, context == "Spatial")
mergedDF <- merge(conceptualScores, spatialScores, by ="id")
joinedDF <- rbind(conceptualScores, spatialScores)
bothTasksDF <- ddply(joinedDF, .(id, environment, contextOrder), plyr::summarize, meanScore = mean(meanScore))
randomDF <- read.csv("../rationalModels/random.csv") #load random model
joinedDF$contextOrder <- factor(joinedDF$contextOrder)
levels(joinedDF$contextOrder)<- c("Spatial First", "Conceptual First")
Overall, participants performed far better than chance in both Conceptual (\(t(128)=24.6\), \(p<.001\), \(d=2.2\), \(BF>100\)) and Spatial tasks (\(t(128)=34.6\), \(p<.001\), \(d=3.0\), \(BF>100\)). Let’s now do a two way mixed ANOVA to see how our context x environment design influenced performance.
#Two way mixed ANOVA: context is within, environment is between
dd<-ddply(rbind(conceptualScores, spatialScores), ~id+context+environment, summarise, m=mean(meanScore))
dd$id <- factor(dd$id)
res.aov <- aov(m ~ environment*context + Error(id/context), data=dd)
anova_stats(res.aov)
# Now let's replicate via Robust ANOVA
bwtrim(m ~ environment*context, id = id, data=dd, tr = 0.2) #using 20% trimmed means
Call:
bwtrim(formula = m ~ environment * context, id = id, data = dd,
tr = 0.2)
sppba(m ~ environment*context, id = id, data=dd) #Main fixed effect
Call:
sppba(formula = m ~ environment * context, id = id, data = dd)
Test statistics:
[1] -6.345
Test whether the corrresponding population parameters are the same:
p-value: 0.002
sppbb(m ~ environment*context, id = id, data=dd) #Within-subect effect
Call:
sppbb(formula = m ~ environment * context, id = id, data = dd)
Test statistics:
[1] -4.828
Test whether the corrresponding population parameters are the same:
p-value: 0
#Now compute Bayes factor
invisible(bf <- anovaBF(m ~ environment*context+id, data=dd, whichRandom="id"))
|
| | 0%
|
|=========================== | 20%
|
|====================================================== | 40%
|
|================================================================================= | 60%
|
|============================================================================================================ | 80%
|
|=======================================================================================================================================| 100%
bf
Bayes factor analysis
--------------
[1] context + id : 455178 ±1.03%
[2] environment + id : 13.06263 ±1.43%
[3] context + environment + id : 6293695 ±2.35%
[4] context + environment + context:environment + id : 2376791 ±2.28%
Against denominator:
m ~ id
---
Bayes factor type: BFlinearModel, JZS
Looks like strong evidence for differences.
#Mean performance plots
p1a <- ggplot(joinedDF, aes(x = interaction(context, environment), y = meanScore, color = context))+
geom_boxplot(fill=NA, color = 'black', outlier.shape=NA, width = 0.2)+
geom_line(aes(group=id), color = 'black', alpha = 0.1)+
geom_quasirandom(alpha = 0.7)+
geom_hline(yintercept = mean(randomDF$meanReward), color = 'black', linetype = 'dashed')+
stat_summary(fun.y = mean, shape = 23, geom='point', size = 3, fill = NA, color ='black')+
#facet_grid(~environment)+
ylab("Mean Reward \u00B1SE")+
xlab('')+
annotate('text', x = 1.5, y = 110, label='Rough')+
annotate('text', x = 3.5, y = 110, label='Smooth')+
scale_x_discrete(labels=c("Conceptual", "Spatial", "Conceptual", "Spatial"))+
scale_color_brewer(palette = "Dark2", name = "") +
scale_fill_brewer(palette = "Dark2", name = "") +
geom_signif(y_position = c(95, 97, 103), xmin = c(1,3, 1.5), xmax = c(2,4, 3.5), annotation = c("BF>100","BF = 14", "BF = 12"), color = 'black')+
#geom_signif(comparisons=list( c("Conceptual", "Spatial"), c("Conceptual", "Spatial")), annotations=c("",""), col="black")+ #
theme(text = element_text(size=12, family="sans"),strip.background=element_blank(), legend.key=element_rect(color=NA), legend.position='None')
p1a

Participants earned higher rewards in the Spatial than the Conceptual task (one sample \(t\)-test: \(t(128)=-6.0\), \(p<.001\), \(d=0.5\), \(BF>100\)) and better in smooth than in rough environments (two sample \(t\)-test: \(t(127)=3.1\), \(p=.003\), \(d=0.5\), \(BF=12\)). We also find correlated performance between tasks (\(r=.53\), \(p<.001\), \(BF>100\)).
#statistical tests
ttestPretty(conceptualScores$meanScore, mu=mean(randomDF$meanReward)) #compared to chance
ttestPretty(spatialScores$meanScore, mu=mean(randomDF$meanReward))
#T-tests
ttestPretty(conceptualScores$meanScore, spatialScores$meanScore, var.equal = TRUE, paired=T) #context
ttestPretty(subset(bothTasksDF, environment=="Smooth")$meanScore, subset(bothTasksDF, environment=="Rough")$meanScore, var.equal = TRUE) #environment
corTestPretty(conceptualScores$meanScore, spatialScores$meanScore) #correlated performance
ttestPretty(subset(conceptualScores, environment=='Smooth')$meanScore, subset(spatialScores, environment=="Smooth")$meanScore, var.equal = TRUE, paired=T) #context
ttestPretty(subset(conceptualScores, environment=='Rough')$meanScore, subset(spatialScores, environment=="Rough")$meanScore, var.equal = TRUE, paired=T, maxBF = Inf) #context
Correlation between tasks:
#corTestPretty(conceptualScores$meanScore, spatialScores$meanScore)
p1b <- ggplot(mergedDF, aes(x=meanScore.x, y = meanScore.y, color = environment.x, shape= environment.x)) +
geom_abline(slope=1, intercept=0, linetype='dashed') +
geom_point(alpha=0.9, size = 2.5)+
ylab('Spatial Reward')+
xlab('Conceptual Reward')+
xlim(40,100)+
ylim(40,100) +
annotate("text", x = 50, y = 95, label = "'r = .53' *','* ~~'BF > 100'", parse=TRUE, size=5, family="sans") +
theme(legend.position=c(1,0),legend.justification=c(1,0), strip.background=element_blank(), legend.key=element_rect(color=NA), text = element_text(size=12, family="sans"))+
#scale_color_rickandmorty(name="Environment", palette = "schwifty")+
scale_color_manual(name="Environment", values=c("#24325FFF", '#B7E4F9FF'))+
scale_shape_manual(name="Environment", values= c(17,16))
p1b

Order effect
We find an interesting one-directional order effect. Participants performed better on the conceptual task once they had experience with the spatial task (\(t(127)=2.8\), \(p=.006\), \(d=0.5\), \(BF=6.4\). This was not the case for the spatial task, where performance did not differ if performed first or second (\(t(127)=-1.7\), \(p=.096\), \(d=0.3\), \(BF=.67\)). Thus, experience with spatial search boosted performance on conceptual search, but not vice versa.
df$FirstTask <- ifelse(df$contextOrder==0, 'Spatial First', 'Conceptual First') #which task was performed first?
df$taskOrder <- ifelse((df$FirstTask=="Spatial First" & df$context == "Spatial") |(df$FirstTask=="Conceptual First" & df$context == "Conceptual"), 1, 2 )
df$FirstTask <- factor(df$FirstTask, levels = c("Conceptual First","Spatial First"))
orderDF <- ddply(df, .(id, context, environment, FirstTask, taskOrder), plyr::summarize, meanScore = mean(z))
pOrder <- ggplot(orderDF, aes(x = interaction(context,FirstTask), y = meanScore, fill = context, color = context))+
geom_boxplot( color = 'black', position = position_dodge(width = 1), outlier.shape=NA, width = 0.2, alpha =0)+
geom_quasirandom(alpha = 0.7, dodge.width = 1)+
#geom_line(aes(group=id), color = 'black', alpha = 0.1)+
stat_summary(fun.y = mean, shape = 23, geom='point', size = 3, position = position_dodge(width = 1), color ='black', fill = NA)+
#stat_summary(fun.y=mean, geom='bar', position = position_dodge(width = 1), color='black')+
#stat_summary(fun.data = mean_cl_boot, geom='errorbar', color='black', position = position_dodge(width = 1), width = .2)+
scale_fill_brewer(palette = 'Dark2', name= 'Task')+
scale_color_brewer(palette = 'Dark2', name= 'Task')+
annotate('text', x = 1.5, y = 118, label='Conceptual First')+
annotate('text', x = 3.5, y = 118, label='Spatial First')+
scale_x_discrete(labels=c("Conceptual", "Spatial", "Conceptual", "Spatial"))+
geom_hline(yintercept = mean(randomDF$meanReward), color = 'black', linetype = 'dashed')+
#coord_cartesian(ylim =c(40,120))+
xlab('')+
ylab('Mean Reward ±SE')+
geom_signif(y_position = c(100, 108), xmin = c(1,2), xmax = c(3,4), annotation = c("BF=6.4","BF=0.67"), color = 'black')+
#theme(legend.position=c(0.05,1), legend.justification = c(0,1), legend.direction='horizontal')
theme(legend.position='none')
pOrder

Patterns of Search
Locality of sampling
Let’s look at the patterns in search behavior. First, let’s look at the distance between successive choices.
#compare to random
sampleSize <- 400000
randomDistanceDF <- data.frame(x=sample(x = seq(0:7), size = sampleSize, replace=TRUE), y=sample(x = seq(0:7), size = sampleSize, replace=TRUE), environment=c(rep("Rough",sampleSize/2), rep("Smooth", sampleSize/2)), context = rep(c('Conceptual', 'Spatial'), sampleSize/2))
randomDistanceDF <- randomDistanceDF %>%
mutate(distance = abs((x - lag(x,default = NA)) + abs(y - lag(y,default = NA)) ))
#Add classification of choices as stay, near, or far decisions
localityDF <-ddply(df, ~id+trial+context, plyr::summarize, avgDistance=mean(distance, na.rm=T))
localityDF$choiceType <-ifelse(localityDF$avgDistance==0, "Stay", ifelse(localityDF$avgDistance==1, "Near", "Far"))
localityDF$choiceType <- factor(localityDF$choiceType)
choiceProp <- ddply(na.omit(localityDF),.(id,context), function(x) with(x,data.frame(table(choiceType)/length(choiceType),2)))
choiceProp$choiceType <- factor(choiceProp$choiceType, levels=c("Stay", "Near", "Far"))
Let’s first do an ANOVA here
#Two way mixed ANOVA: context is within, environment is between
dd <-ddply(df, ~id+environment+context, plyr::summarize, avgDistance=mean(distance, na.rm=T))
dd$id <- factor(dd$id)
res.aov <- aov(avgDistance ~ environment*context + Error(id/context), data=dd)
anova_stats(res.aov)
# Now let's replicate via Robust ANOVA
bwtrim(avgDistance ~ environment*context, id = id, data=dd, tr = 0.2) #using 20% trimmed means
Call:
bwtrim(formula = avgDistance ~ environment * context, id = id,
data = dd, tr = 0.2)
sppba(avgDistance ~ environment*context, id = id, data=dd) #Main fixed effect
Call:
sppba(formula = avgDistance ~ environment * context, id = id,
data = dd)
Test statistics:
[1] 0.1143
Test whether the corrresponding population parameters are the same:
p-value: 0.394
sppbb(avgDistance ~ environment*context, id = id, data=dd) #Within-subect effect
Call:
sppbb(formula = avgDistance ~ environment * context, id = id,
data = dd)
Test statistics:
[1] 0.211
Test whether the corrresponding population parameters are the same:
p-value: 0.078
#Now compute Bayes factor
bf = anovaBF(avgDistance ~ environment*context+id, data=dd, whichRandom="id")
|
| | 0%
|
|=========================== | 20%
|
|====================================================== | 40%
|
|================================================================================= | 60%
|
|============================================================================================================ | 80%
|
|=======================================================================================================================================| 100%
bf
Bayes factor analysis
--------------
[1] environment + id : 0.2481661 ±1.34%
[2] context + id : 68.52213 ±2.17%
[3] environment + context + id : 17.07542 ±1.15%
[4] environment + context + environment:context + id : 5.922832 ±4.65%
Against denominator:
avgDistance ~ id
---
Bayes factor type: BFlinearModel, JZS
Let’s plot the results
contextLabels <- c('Conceptual' = 'Conceptual\nTask', 'Spatial' = 'Spatial\nTask', "Rough"="Rough", "Smooth"="Smooth")
p4alt <- ggplot(na.omit(df), aes(x=distance, fill = context, color = context)) +
geom_histogram(aes(y = ..density..*20), position = 'dodge', binwidth=1, color='black')+
stat_density(data = randomDistanceDF, aes(y = ..density..*20), geom="line",color='black', size = .8, bw = 1) +
#geom_density(fill=NA, size = 0.7) +
scale_fill_manual(values=c("#1B9E77", "#D95F02", "Black"), name="") +
scale_color_manual(values = c("#1B9E77", "#D95F02", "Black"), name="") +
ylab("Choices Per Round") +
xlab("Distance Between Choices") +
#xlim(0,6)+
facet_grid(context~environment, labeller = as_labeller(contextLabels))+
scale_x_continuous(breaks = scales::pretty_breaks(n = 5))+
scale_y_continuous(breaks = seq(0, 10, by = 2))+
#ggtitle("Locality of Sampling") +
theme(legend.position='none', strip.background=element_blank(), legend.key=element_rect(color=NA))
p4alt

Let’s try a different version where the differences between task are more salient
contextLabels <- c('Conceptual' = 'Conceptual\nTask', 'Spatial' = 'Spatial\nTask', "Rough"="Rough", "Smooth"="Smooth")
anndf<-data.frame(distance = NA,context = NA,environment = factor("Smooth", levels = c("Rough", "Smooth")), text = 'Random', color = 'black') #for annotation
p4alt <- ggplot(na.omit(df), aes(x=distance, fill = context, color = context)) +
geom_histogram(aes(y = ..density..*20), position = 'identity', binwidth=1, alpha = 0.4)+
stat_density(data = subset(randomDistanceDF, context == 'Conceptual'), aes(y = ..density..*20), geom="line",color='black', size = .8, bw = 1) +
#geom_density(fill=NA, size = 0.7) +
scale_fill_manual(values=c("#1B9E77", "#D95F02", "Black"), name="Task") +
scale_color_manual(values = c("#1B9E77", "#D95F02", "Black"), name="Task") +
ylab("Choices Per Round") +
xlab("Distance Between Choices") +
#xlim(0,6)+
facet_grid(~environment, labeller = as_labeller(contextLabels))+
scale_x_continuous(breaks = scales::pretty_breaks(n = 5))+
scale_y_continuous(breaks = seq(0, 10, by = 2))+
#ggtitle("Locality of Sampling") +
#geom_text(data = anndf, x = 10.5, y = 5, label = "Random", color = 'black', size = 3.5)+
#geom_segment(data = anndf, x = 9, xend = 10, y = 5, yend = 5,colour = "black", size = 1.2)+
theme(legend.position=c(1,1), legend.justification = c(1,1), strip.background=element_blank(), legend.key=element_rect(color=NA))
p4alt

Participants searched over larger distances in the conceptual task than the spatial task (\(t(128)=-3.7\), \(p<.001\), \(d=0.3\), \(BF=59\)). There were no differences across environments (\(t(127)=-0.3\), \(p=.727\), \(d=0.06\), \(BF=.20\)). Note that each trial began on a random selected stimuli. So searching close to the previous selection is not due to a lack of effort. (\(t(128)=-16.2\), \(p<.001\), \(d=1.4\), \(BF>100\))
#Statistical tests reported above
localityDF <- ddply(df, ~id+context,plyr::summarize, avgDistance=mean(distance, na.rm=T))
ttestPretty(subset(localityDF, context == 'Spatial')$avgDistance, subset(localityDF, context == 'Conceptual')$avgDistance, var.equal=T, paired=T)
localityDF <- ddply(df, ~id+environment,plyr::summarize, avgDistance=mean(distance, na.rm=T))
ttestPretty(subset(localityDF, environment == 'Smooth')$avgDistance, subset(localityDF, environment == 'Rough')$avgDistance, var.equal=T)
localityDF <- ddply( df, ~id, plyr::summarize, avgDistance=mean(distance, na.rm=T))
ttestPretty(na.omit(localityDF$avgDistance), mu = mean(randomDistanceDF$distance, na.rm=T))
Now let’s classify these choices as either Stay (distance = 0), Near (distance = 1), or Far (distance >1).
#choice prop
localityDF <-ddply(df, ~id+trial+context, plyr::summarize, avgDistance=mean(distance, na.rm=T))
localityDF$distance <-localityDF$avgDistance
randomDistanceDF$id <- 0
randomDistanceDF$context <- 'Random'
localityDF <- rbind(localityDF[,c( "context", "distance", 'id')], randomDistanceDF[,c( "context", "distance", 'id')])
localityDF$choiceType <-ifelse(localityDF$distance==0, "Stay", ifelse(localityDF$distance==1, "Near", "Far"))
localityDF$choiceType <- factor(localityDF$choiceType)
choiceProp <- ddply(na.omit(localityDF),.(id,context),
function(x) with(x,
data.frame(table(choiceType)/length(choiceType),2)))
choiceProp$choiceType <- factor(choiceProp$choiceType, levels=c("Stay", "Near", "Far"))
p4 <- ggplot(na.omit(choiceProp), aes(x=choiceType, y = Freq*20, fill=context, color = context))+
stat_summary(fun.y = mean,geom='bar', position='dodge', color='black') +
stat_summary(fun.data = mean_se, geom = "errorbar", position = position_dodge(width = 0.90), width = 0.2, color='black' ) +
#scale_y_continuous(labels=percent)+
scale_fill_manual(values=c("#1B9E77", "#D95F02", "Black"), name="") +
scale_color_manual(values=c("#1B9E77", "#D95F02", "Black"), name="") +
#scale_fill_rickandmorty()+
ylab('Choices Per Round ±SE')+
xlab("Choice Type")+
#facet_grid(~contextOrder)+
theme(legend.position= c(0.05, 1), legend.justification=c(0,1), strip.background=element_blank(), legend.key=element_rect(color=NA))
p4

This seems to paint the same picture as the distance histograms before. Participants made more stay choices in the spatial task (\(t(128)=-2.7\), \(p=.007\), \(d=0.3\), \(BF=3.4\)) and more far choices in the conceptual task (\(t(128)=2.8\), \(p=.006\), \(d=0.3\), \(BF=4.1\)). There were no differences in near choices (\(t(128)=-0.4\), \(p=.688\), \(d=0.05\), \(BF=.11\)).
Search Trajectories
We have this really rich data about how participants navigated the search space. Let’s first look at the number of steps participants took before making a selection
df$steps <- sapply(df$trajectories, function(i) length(fromJSON(as.character(i))))
trajDF <- df%>% group_by(id,context) %>% dplyr::summarize(avgSteps=mean(steps, na.rm=T))
trajContextDF <- df%>% group_by(id,context) %>% dplyr::summarize(avgSteps=mean(steps, na.rm=T))
traEnvjDF <- df%>% group_by(id,environment) %>% dplyr::summarize(avgSteps=mean(steps, na.rm=T))
levels(df$contextOrder)<- c("Spatial First", "Conceptual First")
#comparing context
ggplot(df, aes(x = context, y = steps, fill = context))+
stat_summary(fun.y = mean, geom = "bar", position = "dodge", color='black') +
stat_summary(fun.data = mean_se, geom = "errorbar", position = position_dodge(width = 0.90), width = 0.2, color = 'black' ) +
theme(legend.position='right', strip.background=element_blank(), legend.key=element_rect(color=NA), legend.background=element_blank(), text = element_text(size=16, family="sans"))+
#coord_cartesian(ylim=c(0,8)) +
xlab("")+
scale_fill_brewer(palette = "Dark2", name="") +
facet_grid(~contextOrder)+
ylab("Mean Number of Steps \u00B1SE")

medians <- df%>% group_by(environment,context) %>% dplyr::summarize(steps=mean(steps, na.rm=T))
contextLabels <- c('Conceptual' = 'Conceptual\nTask', 'Spatial' = 'Spatial\nTask', "Rough"="Rough", "Smooth"="Smooth")
trajectoryplot <- ggplot(na.omit(df), aes(x=steps, fill = context, color = context)) +
geom_histogram(aes(y = ..density..*20), position = 'dodge', binwidth=1, color='black')+
#stat_density(data = as.data.frame(randomDF), aes(value),geom="line",color='black', size = .8, linetype='dashed') +
#geom_density(fill=NA, size = 0.7) +
scale_fill_manual(values=c("#1B9E77", "#D95F02", "Black"), name="") +
scale_color_manual(values = c("#1B9E77", "#D95F02", "Black"), name="") +
geom_vline(data = medians, aes(xintercept = steps), linetype = 'dashed', size =.7)+
ylab("Choices Per Round") +
xlab("Trajectory Length") +
#xlim(0,6)+
facet_grid(context~environment, labeller = as_labeller(contextLabels))+
scale_x_continuous(breaks = scales::pretty_breaks(n = 5), limits = c(0,20))+
scale_y_continuous(breaks = seq(0, 3, by = 1))+
#ggtitle("Locality of Sampling") +
theme(legend.position='none', strip.background=element_blank(), legend.key=element_rect(color=NA))
trajectoryplot

Participants had longer trajectories in the contextual task (\(t(128)=-10.7\), \(p<.001\), \(d=1.0\), \(BF>100\)), although there were no differences across environments (\(t(127)=1.3\), \(p=.213\), \(d=0.2\), \(BF=.38\)).
ttestPretty(subset(trajContextDF, context == 'Spatial')$avgSteps, subset(trajContextDF, context == 'Conceptual')$avgSteps, var.equal=T, paired=T)
[1] "$t(128)=-10.7$, $p<.001$, $d=1.0$, $BF>100$"
ttestPretty(subset(traEnvjDF, environment == 'Smooth')$avgSteps, subset(traEnvjDF, environment == 'Rough')$avgSteps, var.equal=T)
[1] "$t(127)=1.3$, $p=.213$, $d=0.2$, $BF=.38$"
Attentional Biases
Let’s also look at the trajectories decomposed into the vertical/stripe frequency dimension vs. horizontal/tilt dimension. The figure below shows the proportion of participant inputs corresponding to each dimension, where we see an higher proportion of inputs given to the vertical/stripe frequency dimension in both tasks, relative to the horizontal/tilt dimension.
#compile total button pressess for each dimension
df$trajLeft <- sapply(df$trajectories, function(i) sum(fromJSON(as.character(i)) == 37))
df$trajUp <- sapply(df$trajectories, function(i) sum(fromJSON(as.character(i)) == 38))
df$trajRight <- sapply(df$trajectories, function(i) sum(fromJSON(as.character(i)) == 39))
df$trajDown <- sapply(df$trajectories, function(i) sum(fromJSON(as.character(i)) == 40))
trajDirDF <- ddply(df, ~id+context+environment, plyr::summarize, horizontal = (sum(trajLeft)+sum(trajRight))/sum(steps), vertical = (sum(trajUp)+sum(trajDown))/sum(steps)) #compute average per participant per trial
trajDirDF <- trajDirDF %>% gather(direction, p, horizontal:vertical, factor_key=TRUE) #wide to long
trajDirDF$direction <- factor(trajDirDF$direction)
levels(trajDirDF$direction)<- c('Horizontal/\nRotation', 'Vertical/\nStripes')
trajDirDF$id <- factor(trajDirDF$id)
#plot
inputdir <- ggplot(trajDirDF, aes(x = direction, y = p, fill = context))+
stat_summary(fun.y = mean, geom = "bar", position = "dodge", color='black') +
stat_summary(fun.data = mean_cl_boot, geom = "errorbar", position = position_dodge(width = 0.90), width = 0.2, color = 'black' ) +
theme(legend.position='right', strip.background=element_blank(), legend.key=element_rect(color=NA), legend.background=element_blank())+
#coord_cartesian(ylim=c(0,8)) +
xlab("Input")+
scale_fill_brewer(palette = "Dark2", name="Task") +
facet_grid(~environment)+
ylab("Proportion of Inputs \u00B1 95% CI") +
theme(legend.position = 'top')
inputdir

We formally define the difference in attention \(\Delta_{\textrm{dim}} = P(\textrm{vertical/stripe frequency}) - P(\textrm{horizontal/tilt})\), where positive values indicate a stronger bias towards the vertical/stripe frequency dimension. Running a two-way mixed ANOVA reveals that attentional bias was influenced by the interaction of task order and task (\(F(1,127) = 8.1\), \(p=.005\), \(\eta^2=.02\), \(BF>100\)).
#add task order into trajDifDF
trajDirDF$FirstTask <- df[match(trajDirDF$id, df$id),"FirstTask"]
diffDF <- ddply(trajDirDF, ~id+environment+context+FirstTask, plyr::summarize, pdiff = diff(p)) #calculate the difference in proportion of key presses over contexts (positive is more vertical, while negative is more horizontal )
#Anova
res.aov <- aov(p ~ context*FirstTask + Error(id/context), data = subset(trajDirDF, direction =='Horizontal/\nRotation'))
anova_stats(res.aov)
#Replication with robust ANOVA
bwtrim(p ~ context*FirstTask, id = id, data=subset(trajDirDF, direction =='Horizontal/\nRotation'), tr = 0.2) #using 20% trimmed means
Call:
bwtrim(formula = p ~ context * FirstTask, id = id, data = subset(trajDirDF,
direction == "Horizontal/\nRotation"), tr = 0.2)
#Bayes factor of ANOVA
invisible(bf <- anovaBF(p ~ context*FirstTask , data=subset(trajDirDF, direction =='Horizontal/\nRotation'), whichRandom="id"))
|
| | 0%
|
|================================== | 25%
|
|==================================================================== | 50%
|
|===================================================================================================== | 75%
|
|=======================================================================================================================================| 100%
bf
Bayes factor analysis
--------------
[1] context : 1973.07 ±0%
[2] FirstTask : 25.80392 ±0%
[3] context + FirstTask : 76972.02 ±0.75%
[4] context + FirstTask + context:FirstTask : 258199.7 ±1%
Against denominator:
Intercept only
---
Bayes factor type: BFlinearModel, JZS
pAttentionTaskOrder <- ggplot(diffDF, aes(x = context, y = pdiff, fill = context))+
stat_summary(fun.y = mean, geom='bar', color='black')+
stat_summary(fun.data = mean_cl_boot, geom='errorbar', color = 'black', width = 0.2)+
facet_grid(~FirstTask)+
theme(legend.position='none', strip.background=element_blank(), legend.key=element_rect(color=NA), legend.background=element_blank())+
#coord_cartesian(ylim=c(0,8)) +
xlab("")+
ylab(expression( Delta[dim]))+
scale_fill_brewer(palette = "Dark2", name="Task")
pAttentionTaskOrder

While participants were more biased towards the vertical/stripe frequency dimension in the conceptual task when the conceptual task was performed first (\(t(66)=-6.0\), \(p<.001\), \(d=0.7\), \(BF>100\)), these differences disappeared when the spatial task was performed first (\(t(61)=-1.6\), \(p=.118\), \(d=0.2\), \(BF=.45\)).
ttestPretty(subset(diffDF, FirstTask == 'Conceptual First' & context == 'Spatial')$pdiff- subset(diffDF, FirstTask == 'Conceptual First' & context == 'Conceptual')$pdiff, mu=0)
ttestPretty(subset(diffDF, FirstTask == 'Spatial First' & context == 'Spatial')$pdiff- subset(diffDF, FirstTask == 'Spatial First' & context == 'Conceptual')$pdiff, mu=0)
Does unequal preference for one of the feature dimensions influence performance? The results are presented in the figure below, where each pair of dots is a single participant, and the connecting line shows the change in score and change in attentional bias \(\Delta_{\textrm{dim}}\) across tasks.
perfDF<- ddply(df, ~id+environment+context+FirstTask, plyr::summarize, score = mean(z))
diffDF$score <- perfDF$score #task specific score
pScoreAttention <- ggplot(diffDF, aes(x = pdiff, y = score, color =context))+
geom_point(alpha = 0.8) +
geom_line(aes(group=id), color = 'black', alpha = 0.1)+
facet_grid(~FirstTask)+
scale_color_brewer(palette = "Dark2", name="Task") +
#geom_smooth(method = 'lm')+
xlab(expression( Delta[dim]))+
ylab('Mean Score')+
theme(legend.position='top', strip.background=element_blank(), legend.key=element_rect(color=NA))
We find a negative relationship between score and attention for the conceptual task only in the conceptual first order (\(r_{\tau}=-.31\), \(p<.001\), \(BF>100\)), but not in the spatial first order (\(r_{\tau}=-.07\), \(p=.392\), \(BF=.24\)). There were no relationships between score and attention in the spatial task in either order (spatial first: \(r_{\tau}=.03\), \(p=.738\), \(BF=.17\); conceptual first: \(r_{\tau}=-.03\), \(p=.750\), \(BF=.17\)). Thus, strong attentional biases predicted lower score, but only in the conceptual first task order.
#spatial first
corTestPretty(subset(diffDF, FirstTask == 'Spatial First' & context == 'Spatial')$pdiff, subset(diffDF, FirstTask == 'Spatial First' & context == 'Spatial')$score, method = 'kendall')
corTestPretty(subset(diffDF, FirstTask == 'Spatial First' & context == 'Conceptual')$pdiff, subset(diffDF, FirstTask == 'Spatial First' & context == 'Conceptual')$score, method = 'kendall')
corTestPretty(subset(diffDF, FirstTask == 'Conceptual First' & context == 'Spatial')$pdiff, subset(diffDF, FirstTask == 'Conceptual First' & context == 'Spatial')$score, method = 'kendall')
corTestPretty(subset(diffDF, FirstTask == 'Conceptual First' & context == 'Conceptual')$pdiff, subset(diffDF, FirstTask == 'Conceptual First' & context == 'Conceptual')$score, method = 'kendall')
We now look at differences in attentional biases between tasks. We define \(\Delta_{\textrm{task}} = \Delta_{\textrm{dim}}^{\textrm{Spatial}} - \Delta_{\textrm{dim}}^{\textrm{Conceptual}}\). This difference of differences is a bit more difficult to interpret, but recall that \(\Delta_{\textrm{dim}}\) tended to be positive, since participants attended more towards the vertical/stripe frequency dimension in both tasks. Thus, \(\Delta_{\textrm{task}}\) is positive if participants were more biased towards the vertical/stripe frequency dimension in the spatial task. Vice versa, \(\Delta_{\textrm{task}}\) is negative if participants were more biased towards the vertical/stripe frequency dimension in the conceptual task. Let’s now see the relationship between \(\Delta_{\textrm{task}}\) and change in score:
#Compute delta task
diffByContext <- ddply(diffDF, ~id+environment+FirstTask, plyr::summarize, pdiff = diff(pdiff)) #summarize out context; pdiff spatial - pdiff conceptual
#Add score difference
taskperfDF <- ddply(df, ~id+environment+context+FirstTask, plyr::summarize, score = mean(z)) #mean score for each task
taskPerDiffDF <- ddply(taskperfDF, ~id+environment, plyr::summarize, scoreDiff = diff(score)) #spatial score - conceptual score
diffByContext$scoreDiff <- taskPerDiffDF$scoreDiff #add to dataframe
pScoreDiff <- ggplot(diffByContext, aes(x = pdiff, y = scoreDiff, color = FirstTask, fill = FirstTask))+
geom_point(alpha = 0.8) +
#geom_line(aes(group=id), color = 'black', alpha = 0.1)+
#facet_grid(~FirstTask)+
scale_color_brewer(palette = "Dark2", name="") +
scale_fill_brewer(palette = "Dark2", name="") +
geom_smooth(method = 'lm')+
xlab(expression( Delta[task]))+
ylab('Spatial Score - Conceptual Score')+
theme(legend.position='top', strip.background=element_blank(), legend.key=element_rect(color=NA))
pScoreDiff

Looking first at participants in the Conceptual First condition, we find an anecdotal relationship between \(\Delta_{\textrm{task}}\) and difference in score (\(r_{\tau}=-.20\), \(p=.019\), \(BF=2.4\)). The directionality of this effect is that participants with a stronger bias towards the vertical/stripe frequency dimension in the conceptual task tended to have a lower score in the conceptual task relative to the spatial task. We find no relationship between \(\Delta_{\textrm{task}}\) and difference in score for the Spatial First condition (\(r_{\tau}=-.04\), \(p=.666\), \(BF=.18\)). An outstanding question is whether this shift in attention is responsible for the transfer effect, or is merely an artifact of participants being more capable of navigating the conceptual domain after prior experience with the spatial tasks. While these analyses provide further clarification about the role of attention, the exact relationship between attention (as measured by input frequency) and generalization is perhaps outside the scope of our current paper.
corTestPretty(subset(diffByContext, FirstTask == 'Conceptual First')$pdiff, subset(diffByContext, FirstTask == 'Conceptual First')$scoreDiff, method = 'kendall')
corTestPretty(subset(diffByContext, FirstTask == 'Spatial First')$pdiff, subset(diffByContext, FirstTask == 'Spatial First')$scoreDiff, method = 'kendall')
Efficiency
We can also compute the efficiency of their trajectories based on \(\text{efficiency} = \frac{\text{Manhattan Distance from start to selection}}{\text{Steps taken}}\)
efficencyDF <- ddply(df, ~id+context, plyr::summarize, efficiency = mean(movement/steps))
efficiencyPlot <- ggplot(efficencyDF, aes(x = context, y = efficiency, color = context, fill = context))+
geom_boxplot(fill=NA, color = 'black', width = .2, outlier.shape = NA)+
geom_quasirandom(alpha = .7)+
stat_summary(fun.y = mean, geom = "point",color = 'black', fill=NA, shape =23, size = 3 ) +
#coord_cartesian(ylim=c(0,2)) +
xlab('')+
scale_fill_brewer(palette = "Dark2", name="") +
scale_color_brewer(palette = "Dark2", name="") +
theme( legend.position='none', strip.background=element_blank(), legend.background=element_blank(), legend.key=element_rect(color=NA))+
ylab("Efficiency \u00B1SE")
efficiencyPlot

Participants are clearly less efficient in the conceptual task than the spatial task ($t(128)=-20.6$, $p<.001$, $d=1.9$, $BF>100$).
ttestPretty(subset(efficencyDF, context=='Conceptual')$efficiency, subset(efficencyDF, context=='Spatial')$efficiency, paired=T)
Now let’s ask, what factors influence trajectories? Do longer trajectories obtain higher rewards? Yes they do (\(r=.21\), \(p<.001\), \(BF>100\)).
#steps as a function of previous reward
pTrajLengthReward <- ggplot(subset(df,steps<=20), aes(x =steps, y = z, color = context, fill = context))+
#geom_smooth(fill=NA)+
stat_summary(fun.y = mean, geom = "point") +
stat_summary(fun.data = mean_cl_boot, geom = "errorbar") +
coord_cartesian(xlim=c(0,20), ylim=c(0,100)) + #Tukey outlier criterion indicates outliers above 20; min(boxplot.stats(df$steps)$out)
#facet_grid(~environment)+
scale_fill_brewer(palette = "Dark2", name="Task") +
scale_color_brewer(palette = "Dark2", name="Task") +
theme(legend.position=c(1,0.1),legend.justification = c(1,0), strip.background=element_blank(), legend.background=element_blank(), legend.key=element_rect(color=NA))+
ylab("Reward Value ± 95% CI")+
xlab('Trajectory Length')
pTrajLengthReward

We can also look at the entropy of each trajectory (computed over the distribution of directions moved). It seems like participants in the contextual task had higher entropy (consistent with larger step sizes and lower efficiency), and that lower entropy predicts higher reward.
library(entropy)
myent<-function(x){
return(entropy.empirical(table(x)))
}
df$trajEntropy <- sapply(df$trajectories, function(i) myent(fromJSON(as.character(i))))
ggplot(df, aes(x = context, y = trajEntropy, fill = context))+
stat_summary(fun.y = mean,geom='bar', position='dodge', color='black') +
stat_summary(fun.data = mean_se, geom = "errorbar", position = position_dodge(width = 0.90), width = 0.2, color='black' ) +
#scale_y_continuous(labels=percent)+
scale_fill_manual(values=c("#1B9E77", "#D95F02"), name="") +
scale_color_manual(values=c("#1B9E77", "#D95F02"), name="") +
facet_grid(~environment)

ggplot(subset(df, trajEntropy>0), aes(x = trajEntropy, y = z, color = context))+
geom_point(alpha = 0.05)+
geom_smooth(method = 'lm')+
#stat_summary(fun.y = mean, geom = "point") +
#stat_summary(fun.data = mean_cl_boot, geom = "errorbar") +
xlab('Entropy')+ ylab('Reward Value')+
scale_fill_manual(values=c("#1B9E77", "#D95F02"), name="") +
scale_color_manual(values=c("#1B9E77", "#D95F02"), name="") +
facet_grid(~environment)

NA
NA
How were both distance and trajectory length influenced by the previous reward value?
#reward and distance
#corTestPretty(na.omit(df)$distance, na.omit(df)$previousReward)
p5 <- ggplot(na.omit(df), aes(x=distance, y = previousReward, color = context, fill=context)) +
#geom_count(alpha=0.2, show.legend = F, position = position_dodge(width=0.1))+
#scale_size_area(max_size = 5)+
#geom_jitter(alpha=0.05, size=0.5)+
#geom_smooth(method = "lm") +
stat_summary(fun.y = mean, geom = 'line', size=1)+
stat_summary(fun.data = mean_se, geom = 'ribbon', alpha = 0.7, color=NA) +
theme_classic() +
labs(y='Previous Reward Value', x = 'Distance Between Selections')+
scale_x_continuous(breaks = scales::pretty_breaks(n = 5))+
scale_color_brewer(palette = 'Dark2', name="Task")+
scale_fill_brewer( palette = 'Dark2', name="Task")+
#coord_flip()+
theme(legend.position=c(1,1), legend.justification = c(1,1), strip.background=element_blank(), legend.key=element_rect(color=NA), legend.background=element_blank())
p5

It seems like participants move further away from their previous selection when the reward value was low (\(r=-.66\), \(p<.001\), \(BF>100\)), suggesting basic evidence of generalization behavior.
Let’s run a mixed model on these results
#Mixed effects modeling
#Previous reward value and distance between selections
prior <- c(set_prior("normal(0,1)", class = "b"),set_prior("normal(0,1)", class = "sd"))
distanceRewardMM <- run_model(brm(distance ~ 0+ intercept+ previousReward+context+previousReward*context +(1+previousReward*context|id), data=subset(df, !is.na(df$distance)), prior = prior,cores=4, iter = 4000, warmup = 1000, control = list(adapt_delta = 0.99)), modelName = 'distanceRewardMM')
#tab_model(distanceRewardMM) #Really slow!
fixedTerms <- fixef(distanceRewardMM)#Look at fixed terms
#Now generate predictions, removing id as a random effect
xseq <- seq(0,100)
newdat <-data.frame(context = rep(c("Conceptual","Spatial"), each=101), previousReward = rep(xseq,2))
preds <- fitted(distanceRewardMM, re_formula = NA, newdata = newdat, probs = c(0.025, 0.975))
#create new fixed effects dataframe
fixedDF <- data.frame(context = rep(c("Conceptual","Spatial"), each=101), previousReward = rep(xseq,2),
distance = preds[,1], lower = preds[,3], upper = preds[,4] )
p5alt <- ggplot(subset(df, !is.na(df$distance)), aes(previousReward, distance, color = context, fill = context)) +
#geom_hline(yintercept = mean(randomDistanceDF$distance, na.rm=T ), size = 1, color = 'black', linetype='dashed')+
geom_line(data = fixedDF, size = 1)+ #GP is
geom_ribbon(data = fixedDF, aes(ymin=lower, ymax = upper), color = NA, alpha = 0.4 )+
stat_summary(fun.y=mean,geom='point', alpha = 0.8)+
#geom_abline(slope = 1, linetype = 'dashed')+
#coord_cartesian(xlim = c(0,100))+
xlim(c(0,100))+
theme_classic()+
scale_color_brewer(palette = 'Dark2', name="Task")+
scale_fill_brewer( palette = 'Dark2', name="Task")+
#facet_grid(~context, labeller = as_labeller(contextLabels) )+
xlab("Previous Reward Value")+
ylab("Distance Between Selections")+
annotate("text", x = 50, y = 8, label = "paste(italic(b)[prevReward] , \" = -0.06, 95% HPD: [-0.06, -0.06]\")", parse = TRUE)+
theme(legend.position=c(0, 0), legend.justification=c(0,0), strip.background=element_blank(), legend.key=element_blank(), legend.background=element_blank())
p5alt

At ther same time, participants also moved futher away from their initial starting point after observing larger reward values (\(r_{ au}=.18\), \(p<.001\), \(BF>100\)). Note that the there was a random starting position at the beginning of each trial. So the starting point is not the same as the previous selection. A small distance from the initial starting point is indicative of random search behavior, utilizing the randomness of the initialization. The trend indicates that participants made a larger effort to search in a directed fashion after observing large reward values
prior <- c(set_prior("normal(0,1)", class = "b"),set_prior("normal(0,1)", class = "sd"))
distanceInitialMM <- run_model(brm(movement ~0 + intercept +previousReward*context +(1+previousReward*contex|id), data=subset(df, !is.na(df$movement)),
prior = prior,
cores=4, iter = 4000, warmup = 1000, control = list(adapt_delta = 0.99)), modelName = 'distanceInitialMM')
#bayes_R2(distanceInitialMM)
#tab_model(distanceInitialMM)
fixedTerms <- fixef(distanceInitialMM)#Look at fixed terms
#Now generate predictions, removing id as a random effect
xseq <- seq(1,100)
newdat <-data.frame(context = rep(c("Conceptual","Spatial"), each=100), previousReward = rep(xseq,2))
preds <- fitted(distanceInitialMM, re_formula = NA, newdata = newdat, probs = c(0.025, 0.975))
#create new fixed effects dataframe
fixedDF <- data.frame(context = rep(c("Conceptual","Spatial"), each=100), previousReward = rep(xseq,2),
movement = preds[,1], lower = preds[,3], upper = preds[,4] )
p6 <- ggplot(subset(df, !is.na(df$movement)), aes(previousReward, movement, color = context, fill = context)) +
geom_hline(yintercept = mean(randomDistanceDF$distance, na.rm=T ), size = 1, color = 'black', linetype='dashed')+
geom_line(data = fixedDF, size = 1)+ #GP is
geom_ribbon(data = fixedDF, aes(ymin=lower, ymax = upper), color = NA, alpha = 0.4 )+
stat_summary(fun.y=mean,geom='point', alpha = 0.8)+
#geom_abline(slope = 1, linetype = 'dashed')+
#coord_cartesian(xlim = c(0,100))+
xlim(c(0,100))+
theme_classic()+
scale_color_brewer(palette = 'Dark2', name="Task")+
scale_fill_brewer( palette = 'Dark2', name="Task")+
#facet_grid(~context, labeller = as_labeller(contextLabels) )+
xlab("Previous Reward Value")+
ylab("Distance From Initial Position")+
annotate("text", x = 50, y = 8, label = "paste(italic(b)[prevReward] , \" = 0.01, 95% HPD: [0.01, 0.01]\")", parse = TRUE)+
theme(legend.position=c(0, 0.7), legend.justification=c(0,1), strip.background=element_blank(), legend.key=element_blank(), legend.background=element_blank())
p6

LS0tCnRpdGxlOiAiQmVoYXZpb3JhbCBSZXN1bHRzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwotLS0KCkJlaGF2aW9yYWwgcmVzdWx0cy4gTGV0J3MgbG9vayBhdCBob3cgcGFydGljaXBhbnRzIHBlcmZvcm1lZCBpbiB0aGUgdGFzawoKYGBge3IgbWVzc2FnZT1GQUxTRX0KI2hvdXNlIGtlZXBpbmcKcm0obGlzdD1scygpKQojbG9hZCBwYWNrYWdlcwpwYWNrYWdlcyA8LSBjKCdkcGx5cicsJ2Nvd3Bsb3QnLCAnUm1pc2MnLCAnZ2diZWVzd2FybScsICdicm1zJywgJ1dSUzInLCAnQmF5ZXNGYWN0b3InLCdzY2FsZXMnLCAgJ3BseXInLCAncmVzaGFwZTInLCAnZ2dyaWRnZXMnLCAnZ2dwbG90MicsICdqc29ubGl0ZScsICdNQVNTJywgJ2dyaWRFeHRyYScsICdIbWlzYycsICdsc3InLCAncGFuZGVyJywgJ2dnc2lnbmlmJywgJ3JzdGF0aXgnLCAnc2pzdGF0cycsICdlbW1lYW5zJykKaW52aXNpYmxlKGxhcHBseShwYWNrYWdlcywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkKCnRoZW1lX3NldCh0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZT0xMikpCnNvdXJjZSgnLi4vZGF0YVByb2Nlc3NpbmcuUicpIApzb3VyY2UoJy4uL3N0YXRpc3RpY2FsVGVzdHMuUicpCiNXcmFwcGVyIGZvciBicm0gbW9kZWxzIHN1Y2ggdGhhdCBpdCBzYXZlcyB0aGUgZnVsbCBtb2RlbCB0aGUgZmlyc3QgdGltZSBpdCBpcyBydW4sIG90aGVyd2lzZSBpdCBsb2FkcyBpdCBmcm9tIGRpc2sKcnVuX21vZGVsIDwtIGZ1bmN0aW9uKGV4cHIsIG1vZGVsTmFtZSwgcGF0aD0nLi4vYnJtc01vZGVscycsIHJldXNlID0gVFJVRSkgewogIHBhdGggPC0gcGFzdGUwKHBhdGgsJy8nLCBtb2RlbE5hbWUsICIuYnJtIikKICBpZiAocmV1c2UpIHsKICAgIGZpdCA8LSBzdXBwcmVzc1dhcm5pbmdzKHRyeShyZWFkUkRTKHBhdGgpLCBzaWxlbnQgPSBUUlVFKSkKICB9CiAgaWYgKGlzKGZpdCwgInRyeS1lcnJvciIpKSB7CiAgICBmaXQgPC0gZXZhbChleHByKQogICAgc2F2ZVJEUyhmaXQsIGZpbGUgPSBwYXRoKQogIH0KICBmaXQKfQpgYGAKCkZpcnN0LCBsZXQncyBsb2FkIHRoZSBkYXRhLiBUaGVzZSBkYXRhIGltcG9ydCBmdW5jdGlvbnMgYXJlIGRlZmluZWQgaW4gYGRhdGFQcm9jZXNzaW5nLlJgIHdoZXJlIEkgY29udmVydCB0aGUgcmF3IGRhdGEgaW50byBhIHVzdWFibGUgZGF0YWZyYW1lLiAKCmBgYHtyfQpkYXRhRGlyIDwtICcuLi9leHBlcmltZW50RGF0YS9mdWxsLmNzdicgIwpkZiA8LSBkYXRhSW1wb3J0KGRhdGFGaWxlID0gZGF0YURpciAsbm9ybWFsaXplPUYpICNUaGVzZSB0d28gZnVuY3Rpb25zIGFyZSBkZWZpbmVkIGluIGBkYXRhUHJvY2Vzc2luZy5SYAp0cmFqREYgPC0gaW1wb3J0VHJhakRhdGEoZGF0YUZpbGUgPSBkYXRhRGlyLG5vcm1hbGl6ZT1GKQojVHJpbSBsYXN0IHJvdW5kcwpkZjwtIHN1YnNldChkZiwgcm91bmQ8MTApICNMYXN0IHJvdW5kIGlzIHRoZSBib251cyByb3VuZCBhbmQgaXMgbm90IGluY2x1ZGVkIGluIHRoZSBiZWhhdmlvcmFsIGFuYWx5c2lzLCBzaW5jZSB0aGUganVkZ21lbnQgdGFzayBtYXkgYmlhcyBzdWJzZXF1ZW50IHBlcmZvcm1hbmNlCgpuX3JvdW5kcyA9IDkgI3dpdGhvdXQgYm9udXMgcm91bmQKbl90cmlhbHMgPSAyMCAjcGVyIHJvdW5kCmBgYAoKCiMjIERlbW9ncmFwaGljcwpgYGB7ciBlY2hvID0gRkFMU0V9CgojVG90YWwgcGFydGljaXBhbnRzCnBhc3RlMCgnUGFydGljaXBhbnRzOiAnLCBsZW5ndGgodW5pcXVlKGRmJGlkKSkpCgojQWdlCmFnZURGIDwtIGRkcGx5KGRmLCAuKGlkKSwgcGx5cjo6c3VtbWFyaXplLCAgYWdlPWFzLm51bWVyaWModW5pcXVlKGFnZSkpKQpwYXN0ZTAoJ0FnZTogJywgcHJldHR5TnVtKG1lYW4oYWdlREYkYWdlKSApLCAiIMKxICIgLCBwcmV0dHlOdW0oc2QoYWdlREYkYWdlKSkpCgojZ2VuZGVyCmdlbmRlckRGIDwtIGRkcGx5KGRmLCAuKGlkKSwgcGx5cjo6c3VtbWFyaXplLCAgbWFsZT11bmlxdWUoZ2VuZGVyKSkgIzEgaXMgbWFsZSwgMCBpcyBmZW1hbGUKZ2VuZGVyREYkbWFsZSA8LSBhcy5udW1lcmljKGxldmVscyhnZW5kZXJERiRtYWxlKVthcy5pbnRlZ2VyKGdlbmRlckRGJG1hbGUpXSkKcGFzdGUwKCJNYWxlczogIixzdW0oZ2VuZGVyREYkbWFsZSkpCgojdG90YWwgYm9udXMKYm9udXNEZiA8LSAgZGRwbHkoZGYsIC4oaWQpLCBwbHlyOjpzdW1tYXJpemUsICBib251cz1hcy5udW1lcmljKHVuaXF1ZSh0b3RhbEJvbnVzKSkpICNib251cwpwYXN0ZTAoIkVhcm5pbmdzIDoiLCBtZWFuKGJvbnVzRGYkYm9udXMpICArIDgsICIgVVNEIMKxICIsIHByZXR0eU51bShzZChib251c0RmJGJvbnVzKSkpICNpbmNsdWRpbmcgJDkgcGFydGljaXBhdGlvbiBmZWUKCiNkdXJhdGlvbgpkdXJhdGlvbkRGIDwtICBkZHBseShkZiwgLihpZCksIHBseXI6OnN1bW1hcml6ZSwgIGR1cmF0aW9uPWdyaWRfZHVyYXRpb25bMV0gKyBnYWJvcl9kdXJhdGlvblsxXSkgI2JvbnVzIHBsdXMgcGFydGljaXBhdGlvbiBmZWUKcGFzdGUwKCJUYXNrIER1cmF0aW9uOiAiLCBwcmV0dHlOdW0obWVhbihuYS5vbWl0KGR1cmF0aW9uREYkZHVyYXRpb24pKSksICAiIG1pbnMgwrEgIiwgcHJldHR5TnVtKHNkKG5hLm9taXQoZHVyYXRpb25ERiRkdXJhdGlvbikpKSkKCiMgdGltZSBiZXR3ZWVuIHRhc2tzCmdhcCA8LSBkZHBseShkZiwgLihpZCksIHBseXI6OnN1bW1hcml6ZSwgZ2FwID0gdW5pcXVlKGdyaWRfZ2Fib3JfZ2FwKSkKcGFzdGUwKCJHYXAgYmV0d2VlbiB0YXNrczogIiwgcHJldHR5TnVtKG1lYW4obmEub21pdChnYXAkZ2FwKSkpLCAiIGhvdXJzIMKxICIsIHByZXR0eU51bShzZChuYS5vbWl0KGdhcCRnYXApKSkpCgpgYGAKCgojIyBUcmFpbmluZyBQaGFzZQogCkJlZm9yZSB0aGUgbWFpbiBiYW5kaXQgdGFzaywgcGFydGljaXBhbnRzIHBlcmZvcm1lZCBhIHRyYWluaW5nIHBoYXNlIHdoZXJlIHRoZXkgd2VyZSByZXF1aXJlZCB0byBtYXRjaCBhIHRhcmdldCBzdGltdWxpIHVudGlsIGEgbGVhcm5pbmcgY3JpdGVyaW9uIHdhcyBtZXQgKGF0IGxlYXN0IDMyIHRyaWFscyBhbmQgYSBydW4gb2YgOSBvdXQgb2YgMTAgY29ycmVjdCkuIFRoZSB0YXNrIHVzZWQgdGhlIHNhbWUgc3RpbXVsaSBhbmQgaW5wdXRzIGFzIHRoZSBtYWluIGJhbmRpdCB0YXNrLCBhbmQgd2FzIHVzZWQgdG8gZmFtaWxpYXJpemUgcGFydGljaXBhbnRzIGFuZCBoYXZlIHRoZW0gYWNoaWV2ZSBhIHNpbWlsYXIgbGV2ZWwgb2YgZmx1ZW5jeSB3aXRoIGJvdGggc3BhdGlhbCBhbmQgY29uY2VwdHVhbCBkb21haW5zLiBMZXQncyBmaXJzdCBsb29rIGF0IHNvbWUgb2YgdGhlIHJlc3VsdHMuCgpQYXJ0aWNpcGFudHMgaGFkIGEgbG93ZXIgYWNjdXJhY3kgb24gdGhlIGNvbmNlcHR1YWwgdHJhaW5pbmcgKGByIGRhdCA8LSBkZHBseShkZiwgfmlkK2NvbnRleHQsIHBseXI6OnN1bW1hcml6ZSwgdHJhakNvcnJlY3QgPSBtZWFuKHRyYWpDb3JyZWN0KSwgdHJhakF2Z1N0ZXBzID0gbWVhbih0cmFqQXZnU3RlcHMpKSAKdHRlc3RQcmV0dHkoc3Vic2V0KGRhdCwgY29udGV4dCA9PSAnU3BhdGlhbCcpJHRyYWpDb3JyZWN0LCBzdWJzZXQoZGF0LCBjb250ZXh0ID09ICdDb25jZXB0dWFsJykkdHJhakNvcnJlY3QsIHBhaXJlZD1UKWApIGFuZCByZXF1aXJlZCBtb3JlIHRyaWFscyB0byByZWFjaCB0aGUgdHJhaW5pbmcgY3JpdGVyaW9uICgkWj0tNC4xJCwgJHA8LjAwMSQsICRyPS0uNDAkLCAkQkY+MTAwJCksIHdoaWNoIGlzIHRvIGJlIGV4cGVjdGVkIHNpbmNlIGl0IGlzIGludHVpdGl2ZWx5IG1vcmUgZGlmZmljdWx0LiAKCmBgYHtyfQojT3ZlcmFsbCBDb3JyZWN0IGNob2ljZXMKZGF0IDwtIGRkcGx5KGRmLCB+aWQrY29udGV4dCwgcGx5cjo6c3VtbWFyaXplLCB0cmFqQ29ycmVjdCA9IG1lYW4odHJhakNvcnJlY3QpLCB0cmFqQXZnU3RlcHMgPSBtZWFuKHRyYWpBdmdTdGVwcykpCnRyYWpwMWE8LSBnZ3Bsb3QoZGF0LCBhZXMoeCA9IGNvbnRleHQsIHkgPSB0cmFqQ29ycmVjdCwgY29sb3IgPSBjb250ZXh0KSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cD1pZCksY29sb3IgPSAnYmxhY2snLCBhbHBoYSA9IDAuMSkrCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSwgZmlsbD1OQSwgY29sb3IgPSAnYmxhY2snLCB3aWR0aCA9IDAuMSkrCiAgZ2VvbV9xdWFzaXJhbmRvbShhbHBoYSA9IDAuNykrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGdlb209J3BvaW50Jywgc2hhcGU9MjMsIGNvbG9yID0gJ2JsYWNrJywgc2l6ZSA9MykrCiAgeWxhYignUChjb3JyZWN0KScpKwogIHhsYWIoJycpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICIiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJykKdHJhanAxYQoKI1RyaWFscyB1bnRpbCBjb21wbGV0ZQpkYXQgPC0gZGRwbHkodHJhakRGLCB+aWQrY29udGV4dCwgcGx5cjo6c3VtbWFyaXplLCB0cmFqVHJpYWxzID0gbWF4KHRyaWFsKSkKI3R0ZXN0UHJldHR5KHN1YnNldChkYXQsIGNvbnRleHQgPT0gJ1NwYXRpYWwnKSR0cmFqVHJpYWxzLCBzdWJzZXQoZGF0LCBjb250ZXh0ID09ICdDb25jZXB0dWFsJykkdHJhalRyaWFscywgcGFpcmVkPVQpICNEYXRhIGRvZXNuJ3QgbG9vayB2ZXJ5IG5vcm1hbAojcmFua3Rlc3RQcmV0dHkoc3Vic2V0KGRhdCwgY29udGV4dCA9PSAnU3BhdGlhbCcpJHRyYWpUcmlhbHMsIHN1YnNldChkYXQsIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSR0cmFqVHJpYWxzLCBwYWlyZWQ9VCkgI0lzIHRoZXJlIGEgbWVhbmluZnVsIGRpZmZlcmVuY2UgaW4gdGhlIG51bWJlciBvZiB0cmlhbHMgbmVlZGVkIHRvIGZpbmlzaCB0aGUgdHJhaW5pbmcgcGhhc2U/ICNOb3RlIHNvbWV0aW1lcyBCYXllcyBGYWN0b3JzIGRpc3BsYXkgYXMgTkEgd2hlbiB0aGV5IGFyZSB2ZXJ5IGxhcmdlCgp0cmFqQ29tcGxldGUgPC0gZ2dwbG90KGRhdCwgYWVzKHggPSBjb250ZXh0LCB5ID0gdHJhalRyaWFscywgY29sb3IgPSBjb250ZXh0KSkrCiAgZ2VvbV9saW5lKGFlcyhncm91cD1pZCksY29sb3IgPSAnYmxhY2snLCBhbHBoYSA9IDAuMSkrCiAgZ2VvbV9xdWFzaXJhbmRvbSggYWxwaGEgPSAwLjYpKwogIGdlb21fYm94cGxvdChjb2xvcj0nYmxhY2snLCBmaWxsPSBOQSwgd2lkdGggPS4yLCBvdXRsaWVyLnNoYXBlID0gTkEpKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb209J3BvaW50Jywgc2hhcGUgPSAyMyxzaXplPTMsIGNvbG9yID0gJ2JsYWNrJykrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMzIsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICIiKSArCiAgeWxhYignVHJpYWxzIFVudGlsIENvbXBsZXRlJykrCiAgeGxhYignJykrCiAgI2Nvb3JkX2NhcnRlc2lhbih5bGltPWMoMzAsMTI4KSwgKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMzIsNjQsIDk2LCAxMjgpLCBsaW1pdHMgPSBjKDMyLDEyOCkpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykKdHJhakNvbXBsZXRlCgpgYGAKCldlIGNhbiBhbHNvIGxvb2sgYXQgdGhlIG1hZ25pdHVkZSBvZiBlcnJvcnMgdnMuIHRoZSBmcmVxdWVudnkgb2Ygb2NjdXJlbmNlLCB3aGljaCBnaXZlcyB1cyBhIG5pY2UgU2hlcGFyZCAoMTk4Nykgc3R5bGUgZ2VuZXJhbGl6YXRpb24gZ3JhZGllbnQuCmBgYHtyfQojTWFnbml0dWRlIG9mIGVycm9yIHZzLiBmcmVxdWVuY3kKZ3JhZGllbnRERiA8LSBkZHBseSh0cmFqREYsIH5jb250ZXh0K21hbmhhdHRhbkVycm9yLHBseXI6OnN1bW1hcml6ZSwgY291bnRzID0gdGFibGUobWFuaGF0dGFuRXJyb3IpKSAKI05vcm1hbGl6ZSBpbnRvIGEgcGVyY2VudGFnZQpncmFkaWVudERGW2dyYWRpZW50REYkY29udGV4dCA9PSAnQ29uY2VwdHVhbCcsJ1AnXSA8LSBncmFkaWVudERGW2dyYWRpZW50REYkY29udGV4dCA9PSAnQ29uY2VwdHVhbCcsJ2NvdW50cyddL3N1bShncmFkaWVudERGW2dyYWRpZW50REYkY29udGV4dCA9PSAnQ29uY2VwdHVhbCcsJ2NvdW50cyddKQpncmFkaWVudERGW2dyYWRpZW50REYkY29udGV4dCA9PSAnU3BhdGlhbCcsJ1AnXSA8LSBncmFkaWVudERGW2dyYWRpZW50REYkY29udGV4dCA9PSAnU3BhdGlhbCcsJ2NvdW50cyddL3N1bShncmFkaWVudERGW2dyYWRpZW50REYkY29udGV4dCA9PSAnU3BhdGlhbCcsJ2NvdW50cyddKQoKcEVycm9yPC0gZ2dwbG90KGdyYWRpZW50REYsIGFlcyh4ID0gbWFuaGF0dGFuRXJyb3IsIHkgPSBQLCBjb2xvciA9IGNvbnRleHQsIHNoYXBlID0gY29udGV4dCkpKwogIGdlb21fbGluZSgpKwogIGdlb21fcG9pbnQoKSsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbT1jKDAsNSkpKwogIHlsYWIoJ1AoZXJyb3IpJykrCiAgeGxhYignTWFnbml0dWRlIG9mIEVycm9yIChNYW5oYXR0YW4gZGlzdGFuY2UpJykrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lID0gIlRhc2siKSsKICBzY2FsZV9zaGFwZV9tYW51YWwoIHZhbHVlcyA9IGMoMTYsMTUpLG5hbWUgPSAiVGFzayIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDEsMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLDEpKQoKcEVycm9yCmBgYAoKSG93IGRpZCBhY2N1cmFjeSBkaWZmZXIgZm9yIHRoZSBkaWZmZXJlbnQgb3B0aW9ucz8KYGBge3J9CgpzcGF0aWFsQ291bnRzIDwtIGRkcGx5KHN1YnNldCh0cmFqREYsIGNvbnRleHQgPT0gJ1NwYXRpYWwnKSwgLih4LCB5KSwgcGx5cjo6c3VtbWFyaXplLCBjb3JyZWN0ID0gc3VtKHRyYWpDb3JyZWN0KS9sZW5ndGgodHJhakNvcnJlY3QpKQpuYW1lcyhzcGF0aWFsQ291bnRzKSA8LSBjKCJYIiwgIlkiLCAiQWNjdXJhY3kiKQpzcGF0aWFsQ291bnRzJHRhc2sgPC0gJ1NwYXRpYWwnCgpjb25jZXB0Q291bnRzIDwtIGRkcGx5KHN1YnNldChkZiwgY29udGV4dCA9PSAnQ29uY2VwdHVhbCcpLCAuKHgsIHkpLCBwbHlyOjpzdW1tYXJpemUsIGNvcnJlY3QgPSBzdW0odHJhakNvcnJlY3QpL2xlbmd0aCh0cmFqQ29ycmVjdCkpCm5hbWVzKGNvbmNlcHRDb3VudHMpIDwtIGMoIlgiLCAiWSIsICJBY2N1cmFjeSIpCmNvbmNlcHRDb3VudHMkdGFzayA8LSAnQ29uY2VwdHVhbCcKCnRyYWluaW5nQWNjdXJhY3lERiA8LXJiaW5kKHNwYXRpYWxDb3VudHMsIGNvbmNlcHRDb3VudHMpCnRyYWpoZWF0bWFwPC0gZ2dwbG90KHRyYWluaW5nQWNjdXJhY3lERiwgYWVzKHg9WCwgeSA9IFksIGZpbGw9QWNjdXJhY3kpKSArCiAgZ2VvbV90aWxlKCkrCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIsIG5hbWUgPSAnUChjb3JyZWN0KScsbGltaXRzID0gYygwLDEpLGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkrCiAgdGhlbWVfY2xhc3NpYygpICsKICBmYWNldF9ncmlkKH50YXNrKSsKICBjb29yZF9lcXVhbCgpICsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpLCBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLHBhbmVsLmJvcmRlcj1lbGVtZW50X2JsYW5rKCkscGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkscGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkrCiAgbGFicyh4ID0gJycsIHkgPSAnJykKdHJhamhlYXRtYXAKYGBgCgojIyBQZXJmb3JtYW5jZQoKTm93IGxldCdzIGZpbmFsbHkgbG9vayBhdCBwZXJmb3JtYW5jZSBvbiB0aGUgYmFuZGl0IHRhc2suCgpgYGB7cn0KI0NvbnN0cnVjdCBwbG90dGluZyBkYXRhZnJhbWVzCm1lYW5ERiA8LSBkZHBseShkZiwgLihpZCwgY29udGV4dCwgZW52aXJvbm1lbnQsIGNvbnRleHRPcmRlciksIHBseXI6OnN1bW1hcml6ZSwgbWVhblNjb3JlID0gbWVhbih6KSkKY29uY2VwdHVhbFNjb3JlcyA8LSBzdWJzZXQobWVhbkRGLCBjb250ZXh0ID09ICJDb25jZXB0dWFsIikKc3BhdGlhbFNjb3JlcyA8LSBzdWJzZXQobWVhbkRGLCBjb250ZXh0ID09ICJTcGF0aWFsIikKbWVyZ2VkREYgPC0gbWVyZ2UoY29uY2VwdHVhbFNjb3Jlcywgc3BhdGlhbFNjb3JlcywgYnkgPSJpZCIpCmpvaW5lZERGIDwtIHJiaW5kKGNvbmNlcHR1YWxTY29yZXMsIHNwYXRpYWxTY29yZXMpCmJvdGhUYXNrc0RGIDwtIGRkcGx5KGpvaW5lZERGLCAuKGlkLCBlbnZpcm9ubWVudCwgY29udGV4dE9yZGVyKSwgcGx5cjo6c3VtbWFyaXplLCBtZWFuU2NvcmUgPSBtZWFuKG1lYW5TY29yZSkpCnJhbmRvbURGIDwtIHJlYWQuY3N2KCIuLi9yYXRpb25hbE1vZGVscy9yYW5kb20uY3N2IikgI2xvYWQgcmFuZG9tIG1vZGVsCgpqb2luZWRERiRjb250ZXh0T3JkZXIgPC0gZmFjdG9yKGpvaW5lZERGJGNvbnRleHRPcmRlcikKbGV2ZWxzKGpvaW5lZERGJGNvbnRleHRPcmRlcik8LSBjKCJTcGF0aWFsIEZpcnN0IiwgIkNvbmNlcHR1YWwgRmlyc3QiKQoKYGBgCk92ZXJhbGwsIHBhcnRpY2lwYW50cyBwZXJmb3JtZWQgZmFyIGJldHRlciB0aGFuIGNoYW5jZSBpbiBib3RoIENvbmNlcHR1YWwgKCR0KDEyOCk9MjQuNiQsICRwPC4wMDEkLCAkZD0yLjIkLCAkQkY+MTAwJCkgYW5kIFNwYXRpYWwgdGFza3MgKCR0KDEyOCk9MzQuNiQsICRwPC4wMDEkLCAkZD0zLjAkLCAkQkY+MTAwJCkuICBMZXQncyBub3cgZG8gYSB0d28gd2F5IG1peGVkIEFOT1ZBIHRvIHNlZSBob3cgb3VyIGNvbnRleHQgeCBlbnZpcm9ubWVudCBkZXNpZ24gaW5mbHVlbmNlZCBwZXJmb3JtYW5jZS4KCmBgYHtyfQojVHdvIHdheSBtaXhlZCBBTk9WQTogY29udGV4dCBpcyB3aXRoaW4sIGVudmlyb25tZW50IGlzIGJldHdlZW4gCmRkPC1kZHBseShyYmluZChjb25jZXB0dWFsU2NvcmVzLCBzcGF0aWFsU2NvcmVzKSwgfmlkK2NvbnRleHQrZW52aXJvbm1lbnQsIHN1bW1hcmlzZSwgbT1tZWFuKG1lYW5TY29yZSkpCmRkJGlkIDwtIGZhY3RvcihkZCRpZCkKcmVzLmFvdiA8LSBhb3YobSB+IGVudmlyb25tZW50KmNvbnRleHQgKyBFcnJvcihpZC9jb250ZXh0KSwgZGF0YT1kZCkKYW5vdmFfc3RhdHMocmVzLmFvdikKIyBOb3cgbGV0J3MgcmVwbGljYXRlIHZpYSBSb2J1c3QgQU5PVkEKYnd0cmltKG0gfiBlbnZpcm9ubWVudCpjb250ZXh0LCBpZCA9IGlkLCBkYXRhPWRkLCB0ciA9IDAuMikgI3VzaW5nIDIwJSB0cmltbWVkIG1lYW5zCnNwcGJhKG0gfiBlbnZpcm9ubWVudCpjb250ZXh0LCBpZCA9IGlkLCBkYXRhPWRkKSAjTWFpbiBmaXhlZCBlZmZlY3QKc3BwYmIobSB+IGVudmlyb25tZW50KmNvbnRleHQsIGlkID0gaWQsIGRhdGE9ZGQpICNXaXRoaW4tc3ViZWN0IGVmZmVjdAojTm93IGNvbXB1dGUgQmF5ZXMgZmFjdG9yCmludmlzaWJsZShiZiA8LSBhbm92YUJGKG0gfiBlbnZpcm9ubWVudCpjb250ZXh0K2lkLCAgZGF0YT1kZCwgIHdoaWNoUmFuZG9tPSJpZCIpKQpiZgoKYGBgCkxvb2tzIGxpa2Ugc3Ryb25nIGV2aWRlbmNlIGZvciBkaWZmZXJlbmNlcy4KCmBgYHtyfQojTWVhbiBwZXJmb3JtYW5jZSBwbG90cwpwMWEgPC0gZ2dwbG90KGpvaW5lZERGLCBhZXMoeCA9IGludGVyYWN0aW9uKGNvbnRleHQsIGVudmlyb25tZW50KSwgeSA9IG1lYW5TY29yZSwgY29sb3IgPSBjb250ZXh0KSkrCiAgZ2VvbV9ib3hwbG90KGZpbGw9TkEsIGNvbG9yID0gJ2JsYWNrJywgb3V0bGllci5zaGFwZT1OQSwgd2lkdGggPSAwLjIpKwogIGdlb21fbGluZShhZXMoZ3JvdXA9aWQpLCBjb2xvciA9ICdibGFjaycsIGFscGhhID0gMC4xKSsKICBnZW9tX3F1YXNpcmFuZG9tKGFscGhhID0gMC43KSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKHJhbmRvbURGJG1lYW5SZXdhcmQpLCBjb2xvciA9ICdibGFjaycsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIHNoYXBlID0gMjMsIGdlb209J3BvaW50Jywgc2l6ZSA9IDMsIGZpbGwgPSBOQSwgY29sb3IgPSdibGFjaycpKwogICNmYWNldF9ncmlkKH5lbnZpcm9ubWVudCkrCiAgeWxhYigiTWVhbiBSZXdhcmQgXHUwMEIxU0UiKSsKICB4bGFiKCcnKSsKICBhbm5vdGF0ZSgndGV4dCcsIHggPSAxLjUsIHkgPSAxMTAsIGxhYmVsPSdSb3VnaCcpKwogIGFubm90YXRlKCd0ZXh0JywgeCA9IDMuNSwgeSA9IDExMCwgbGFiZWw9J1Ntb290aCcpKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIkNvbmNlcHR1YWwiLCAiU3BhdGlhbCIsICJDb25jZXB0dWFsIiwgIlNwYXRpYWwiKSkrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lID0gIiIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZSA9ICIiKSArCiAgZ2VvbV9zaWduaWYoeV9wb3NpdGlvbiA9IGMoOTUsIDk3LCAxMDMpLCAgeG1pbiA9IGMoMSwzLCAxLjUpLCB4bWF4ID0gYygyLDQsIDMuNSksIGFubm90YXRpb24gPSBjKCJCRj4xMDAiLCJCRiA9IDE0IiwgIkJGID0gMTIiKSwgY29sb3IgPSAnYmxhY2snKSsKICAjZ2VvbV9zaWduaWYoY29tcGFyaXNvbnM9bGlzdCggYygiQ29uY2VwdHVhbCIsICJTcGF0aWFsIiksIGMoIkNvbmNlcHR1YWwiLCAiU3BhdGlhbCIpKSwgYW5ub3RhdGlvbnM9YygiIiwiIiksIGNvbD0iYmxhY2siKSsgIyAKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIsICBmYW1pbHk9InNhbnMiKSxzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpLCBsZWdlbmQucG9zaXRpb249J05vbmUnKQpwMWEKYGBgCgpQYXJ0aWNpcGFudHMgZWFybmVkIGhpZ2hlciByZXdhcmRzIGluIHRoZSBTcGF0aWFsIHRoYW4gdGhlIENvbmNlcHR1YWwgdGFzayAob25lIHNhbXBsZSAkdCQtdGVzdDogJHQoMTI4KT0tNi4wJCwgJHA8LjAwMSQsICRkPTAuNSQsICRCRj4xMDAkKSBhbmQgYmV0dGVyIGluIHNtb290aCB0aGFuIGluIHJvdWdoIGVudmlyb25tZW50cyAodHdvIHNhbXBsZSAkdCQtdGVzdDogJHQoMTI3KT0zLjEkLCAkcD0uMDAzJCwgJGQ9MC41JCwgJEJGPTEyJCkuIFdlIGFsc28gZmluZCBjb3JyZWxhdGVkIHBlcmZvcm1hbmNlIGJldHdlZW4gdGFza3MgKCRyPS41MyQsICRwPC4wMDEkLCAkQkY+MTAwJCkuCgpgYGB7ciAgZXZhbD1GLCBlY2hvPVR9CiNzdGF0aXN0aWNhbCB0ZXN0cwp0dGVzdFByZXR0eShjb25jZXB0dWFsU2NvcmVzJG1lYW5TY29yZSwgbXU9bWVhbihyYW5kb21ERiRtZWFuUmV3YXJkKSkgI2NvbXBhcmVkIHRvIGNoYW5jZQp0dGVzdFByZXR0eShzcGF0aWFsU2NvcmVzJG1lYW5TY29yZSwgbXU9bWVhbihyYW5kb21ERiRtZWFuUmV3YXJkKSkKCiNULXRlc3RzCnR0ZXN0UHJldHR5KGNvbmNlcHR1YWxTY29yZXMkbWVhblNjb3JlLCBzcGF0aWFsU2NvcmVzJG1lYW5TY29yZSwgdmFyLmVxdWFsID0gVFJVRSwgcGFpcmVkPVQpICNjb250ZXh0CnR0ZXN0UHJldHR5KHN1YnNldChib3RoVGFza3NERiwgZW52aXJvbm1lbnQ9PSJTbW9vdGgiKSRtZWFuU2NvcmUsIHN1YnNldChib3RoVGFza3NERiwgZW52aXJvbm1lbnQ9PSJSb3VnaCIpJG1lYW5TY29yZSwgdmFyLmVxdWFsID0gVFJVRSkgI2Vudmlyb25tZW50CmNvclRlc3RQcmV0dHkoY29uY2VwdHVhbFNjb3JlcyRtZWFuU2NvcmUsIHNwYXRpYWxTY29yZXMkbWVhblNjb3JlKSAjY29ycmVsYXRlZCBwZXJmb3JtYW5jZQp0dGVzdFByZXR0eShzdWJzZXQoY29uY2VwdHVhbFNjb3JlcywgZW52aXJvbm1lbnQ9PSdTbW9vdGgnKSRtZWFuU2NvcmUsIHN1YnNldChzcGF0aWFsU2NvcmVzLCBlbnZpcm9ubWVudD09IlNtb290aCIpJG1lYW5TY29yZSwgdmFyLmVxdWFsID0gVFJVRSwgcGFpcmVkPVQpICNjb250ZXh0CnR0ZXN0UHJldHR5KHN1YnNldChjb25jZXB0dWFsU2NvcmVzLCBlbnZpcm9ubWVudD09J1JvdWdoJykkbWVhblNjb3JlLCBzdWJzZXQoc3BhdGlhbFNjb3JlcywgZW52aXJvbm1lbnQ9PSJSb3VnaCIpJG1lYW5TY29yZSwgdmFyLmVxdWFsID0gVFJVRSwgcGFpcmVkPVQsIG1heEJGID0gSW5mKSAjY29udGV4dAoKYGBgCkNvcnJlbGF0aW9uIGJldHdlZW4gdGFza3M6CgpgYGB7cn0KI2NvclRlc3RQcmV0dHkoY29uY2VwdHVhbFNjb3JlcyRtZWFuU2NvcmUsIHNwYXRpYWxTY29yZXMkbWVhblNjb3JlKQpwMWIgPC0gZ2dwbG90KG1lcmdlZERGLCBhZXMoeD1tZWFuU2NvcmUueCwgeSA9IG1lYW5TY29yZS55LCBjb2xvciA9IGVudmlyb25tZW50LngsIHNoYXBlPSBlbnZpcm9ubWVudC54KSkgKwogIGdlb21fYWJsaW5lKHNsb3BlPTEsIGludGVyY2VwdD0wLCBsaW5ldHlwZT0nZGFzaGVkJykgKwogIGdlb21fcG9pbnQoYWxwaGE9MC45LCBzaXplID0gMi41KSsKICB5bGFiKCdTcGF0aWFsIFJld2FyZCcpKwogIHhsYWIoJ0NvbmNlcHR1YWwgUmV3YXJkJykrCiAgeGxpbSg0MCwxMDApKwogIHlsaW0oNDAsMTAwKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gNTAsIHkgPSA5NSwgbGFiZWwgPSAiJ3IgPSAuNTMnIConLCcqIH5+J0JGID4gMTAwJyIsIHBhcnNlPVRSVUUsIHNpemU9NSwgZmFtaWx5PSJzYW5zIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDEsMCksbGVnZW5kLmp1c3RpZmljYXRpb249YygxLDApLCBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpLCB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTIsICBmYW1pbHk9InNhbnMiKSkrCiAgI3NjYWxlX2NvbG9yX3JpY2thbmRtb3J0eShuYW1lPSJFbnZpcm9ubWVudCIsIHBhbGV0dGUgPSAic2Nod2lmdHkiKSsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZT0iRW52aXJvbm1lbnQiLCB2YWx1ZXM9YygiIzI0MzI1RkZGIiwgJyNCN0U0RjlGRicpKSsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZT0iRW52aXJvbm1lbnQiLCB2YWx1ZXM9IGMoMTcsMTYpKQpwMWIKYGBgCgojIyMgT3JkZXIgZWZmZWN0CgpXZSBmaW5kIGFuIGludGVyZXN0aW5nIG9uZS1kaXJlY3Rpb25hbCBvcmRlciBlZmZlY3QuIFBhcnRpY2lwYW50cyBwZXJmb3JtZWQgYmV0dGVyIG9uIHRoZSBjb25jZXB0dWFsIHRhc2sgb25jZSB0aGV5IGhhZCBleHBlcmllbmNlIHdpdGggdGhlIHNwYXRpYWwgdGFzayAoYHIgdHRlc3RQcmV0dHkoc3Vic2V0KGNvbmNlcHR1YWxTY29yZXMsIGNvbnRleHRPcmRlcj09MCkkbWVhblNjb3JlLCBzdWJzZXQoY29uY2VwdHVhbFNjb3JlcywgY29udGV4dE9yZGVyPT0xKSRtZWFuU2NvcmUsIHZhci5lcXVhbCA9IFRSVUUpYC4gVGhpcyB3YXMgbm90IHRoZSBjYXNlIGZvciB0aGUgc3BhdGlhbCB0YXNrLCB3aGVyZSBwZXJmb3JtYW5jZSBkaWQgbm90IGRpZmZlciBpZiBwZXJmb3JtZWQgZmlyc3Qgb3Igc2Vjb25kIChgciB0dGVzdFByZXR0eShzdWJzZXQoc3BhdGlhbFNjb3JlcywgY29udGV4dE9yZGVyPT0wKSRtZWFuU2NvcmUsIHN1YnNldChzcGF0aWFsU2NvcmVzLCBjb250ZXh0T3JkZXI9PTEpJG1lYW5TY29yZSwgdmFyLmVxdWFsID0gVFJVRSlgKS4gIFRodXMsIGV4cGVyaWVuY2Ugd2l0aCBzcGF0aWFsIHNlYXJjaCBib29zdGVkIHBlcmZvcm1hbmNlIG9uIGNvbmNlcHR1YWwgc2VhcmNoLCBidXQgbm90IHZpY2UgdmVyc2EuCgpgYGB7cn0KZGYkRmlyc3RUYXNrIDwtIGlmZWxzZShkZiRjb250ZXh0T3JkZXI9PTAsICdTcGF0aWFsIEZpcnN0JywgJ0NvbmNlcHR1YWwgRmlyc3QnKSAjd2hpY2ggdGFzayB3YXMgcGVyZm9ybWVkIGZpcnN0PwpkZiR0YXNrT3JkZXIgPC0gaWZlbHNlKChkZiRGaXJzdFRhc2s9PSJTcGF0aWFsIEZpcnN0IiAmIGRmJGNvbnRleHQgPT0gIlNwYXRpYWwiKSB8KGRmJEZpcnN0VGFzaz09IkNvbmNlcHR1YWwgRmlyc3QiICYgZGYkY29udGV4dCA9PSAiQ29uY2VwdHVhbCIpLCAxLCAyICkgCmRmJEZpcnN0VGFzayA8LSBmYWN0b3IoZGYkRmlyc3RUYXNrLCBsZXZlbHMgPSBjKCJDb25jZXB0dWFsIEZpcnN0IiwiU3BhdGlhbCBGaXJzdCIpKQpvcmRlckRGIDwtIGRkcGx5KGRmLCAuKGlkLCBjb250ZXh0LCBlbnZpcm9ubWVudCwgRmlyc3RUYXNrLCB0YXNrT3JkZXIpLCBwbHlyOjpzdW1tYXJpemUsIG1lYW5TY29yZSA9IG1lYW4oeikpCgpwT3JkZXIgPC0gZ2dwbG90KG9yZGVyREYsIGFlcyh4ID0gaW50ZXJhY3Rpb24oY29udGV4dCxGaXJzdFRhc2spLCB5ID0gbWVhblNjb3JlLCBmaWxsID0gY29udGV4dCwgY29sb3IgPSBjb250ZXh0KSkrCiAgZ2VvbV9ib3hwbG90KCBjb2xvciA9ICdibGFjaycsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgb3V0bGllci5zaGFwZT1OQSwgd2lkdGggPSAwLjIsIGFscGhhID0wKSsKICBnZW9tX3F1YXNpcmFuZG9tKGFscGhhID0gMC43LCBkb2RnZS53aWR0aCA9IDEpKwogICNnZW9tX2xpbmUoYWVzKGdyb3VwPWlkKSwgY29sb3IgPSAnYmxhY2snLCBhbHBoYSA9IDAuMSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgc2hhcGUgPSAyMywgZ2VvbT0ncG9pbnQnLCBzaXplID0gMywgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCBjb2xvciA9J2JsYWNrJywgZmlsbCA9IE5BKSsKICAjc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGdlb209J2JhcicsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwgY29sb3I9J2JsYWNrJykrCiAgI3N0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfYm9vdCwgZ2VvbT0nZXJyb3JiYXInLCBjb2xvcj0nYmxhY2snLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHdpZHRoID0gLjIpKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAnRGFyazInLCBuYW1lPSAnVGFzaycpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0gJ1Rhc2snKSsKICBhbm5vdGF0ZSgndGV4dCcsIHggPSAxLjUsIHkgPSAxMTgsIGxhYmVsPSdDb25jZXB0dWFsIEZpcnN0JykrCiAgYW5ub3RhdGUoJ3RleHQnLCB4ID0gMy41LCB5ID0gMTE4LCBsYWJlbD0nU3BhdGlhbCBGaXJzdCcpKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIkNvbmNlcHR1YWwiLCAiU3BhdGlhbCIsICJDb25jZXB0dWFsIiwgIlNwYXRpYWwiKSkrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gbWVhbihyYW5kb21ERiRtZWFuUmV3YXJkKSwgY29sb3IgPSAnYmxhY2snLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSsKICAjY29vcmRfY2FydGVzaWFuKHlsaW0gPWMoNDAsMTIwKSkrCiAgeGxhYignJykrCiAgeWxhYignTWVhbiBSZXdhcmQgwrFTRScpKwogIGdlb21fc2lnbmlmKHlfcG9zaXRpb24gPSBjKDEwMCwgMTA4KSwgIHhtaW4gPSBjKDEsMiksIHhtYXggPSBjKDMsNCksIGFubm90YXRpb24gPSBjKCJCRj02LjQiLCJCRj0wLjY3IiksIGNvbG9yID0gJ2JsYWNrJykrCiAgI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuMDUsMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygwLDEpLCBsZWdlbmQuZGlyZWN0aW9uPSdob3Jpem9udGFsJykKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKQpwT3JkZXIKYGBgCgoKIyMgTGVhcm5pbmcgb3ZlciB0cmlhbHMgYW5kIHJvdW5kcwpQYXJ0aWNpcGFudHMgaW1wcm92ZWQgc3Ryb25nbHkgb3ZlciB0cmlhbHMgKFBlYXJzb24gY29ycmVsYXRpb24gYmV0d2VlbiBzY29yZSBhbmQgdHJpYWwgbnVtYmVyOiBgciB0ZGYgPC0gZGRwbHkoZGYsIC4odHJpYWwpLCBwbHlyOjpzdW1tYXJpemUsIG1lYW5TY29yZT1tZWFuKHopKQpjb3JUZXN0UHJldHR5KHRkZiRtZWFuU2NvcmUsIHRkZiR0cmlhbCkgYCkgYW5kIHRvIGEgbGVzc2VyIGV4dGVudCBvdmVyIHJvdW5kcyAoYHIgcmRmIDwtIGRkcGx5KGRmLCAuKHJvdW5kKSwgcGx5cjo6c3VtbWFyaXplLCBtZWFuU2NvcmU9bWVhbih6KSkKY29yVGVzdFByZXR0eShyZGYkbWVhblNjb3JlLCByZGYkcm91bmQpYCkuCmBgYHtyfQojTWVhbiBzY29yZSBvdmVyIHRyaWFsCnRyaWFsREYgPC0gZGRwbHkoZGYsIC4oaWQsIGNvbnRleHQsIGVudmlyb25tZW50LCB0cmlhbCksIHBseXI6OnN1bW1hcml6ZSwgbWVhblNjb3JlPW1lYW4oeikpCnJhbmRvbURGIDwtIHJlYWQuY3N2KCIuLi9yYXRpb25hbE1vZGVscy9yYW5kb20uY3N2IikgI2xvYWQgcmFuZG9tIG1vZGVsCgpwM2EgPC0gZ2dwbG90KHRyaWFsREYsIGFlcyh4PXRyaWFsLCB5ID0gbWVhblNjb3JlLCBjb2xvciA9IGNvbnRleHQpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICdsaW5lJykrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSxhZXMgKCBmaWxsPWNvbnRleHQpLCBnZW9tID0gJ3JpYmJvbicsIGFscGhhID0gMC43LCBjb2xvcj1OQSkgKwogIHN0YXRfc3VtbWFyeShkYXRhID0gcmFuZG9tREYsIGFlcyh4PXRyaWFsLCB5ID0gbWVhblJld2FyZCksIGZ1bi55ID0gbWVhbiwgZ2VvbT0nbGluZScsIGNvbG9yID0gJ2JsYWNrJywgZmlsbD1OQSwgbGluZXR5cGUgPSAnZGFzaGVkJykrCiAgI2dlb21faGxpbmUoeWludGVyY2VwdCA9ICA1MCwgbGluZXR5cGUgPSAnZGFzaGVkJywgY29sb3IgPSAnYmxhY2snKSsKICBmYWNldF9ncmlkKH5lbnZpcm9ubWVudCkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siICkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZT0iVGFzayIpICsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09Yyg0OSw5NSkpKwogIHlsYWIoIk1lYW4gUmV3YXJkIFx1MDBCMVNFIikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcm91bmQoc2VxKDAsMjAsIGJ5ID0gNSksMSkpKwogIHhsYWIoIlRyaWFsIikrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMSwgMC4xNSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uPWMoMSwwKSwgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5rZXk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkpCnAzYQoKI01lYW4gc2NvcmUgb3ZlciByb3VuZApyb3VuZERGIDwtIGRkcGx5KGRmLCAuKGlkLCBjb250ZXh0LCBlbnZpcm9ubWVudCwgcm91bmQpLCBwbHlyOjpzdW1tYXJpemUsIG1lYW5TY29yZT1tZWFuKHopKQoKcFJvdW5kIDwtIGdncGxvdChyb3VuZERGLCBhZXMoeD1yb3VuZCwgeSA9IG1lYW5TY29yZSwgY29sb3IgPSBjb250ZXh0ICkpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gJ2xpbmUnKSsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLGFlcyhmaWxsPWNvbnRleHQpLCBnZW9tID0gJ3JpYmJvbicsIGFscGhhID0gMC43LCBjb2xvcj1OQSkgKwogIHN0YXRfc3VtbWFyeShkYXRhID0gcmFuZG9tREYsIGFlcyh4PXRyaWFsLCB5ID0gbWVhblJld2FyZCksIGZ1bi55ID0gbWVhbiwgZ2VvbT0nbGluZScsIGNvbG9yID0gJ2JsYWNrJywgZmlsbD1OQSwgbGluZXR5cGUgPSAnZGFzaGVkJykrCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDkpKSsKICBmYWNldF9ncmlkKH5lbnZpcm9ubWVudCkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lPSJUYXNrIikgKwogIHlsYWIoIk1lYW4gUmV3YXJkIFx1MDBCMVNFIikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcm91bmQoc2VxKDAsOSwgYnkgPSAyKSwxKSkrCiAgI2Nvb3JkX2NhcnRlc2lhbih5bGltPWMoMjAsNTApKSsKICB4bGFiKCJSb3VuZCIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuMDUsIDAuMSksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uPWMoMCwwKSwgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKQoKcFJvdW5kCmBgYAoKIyMgUGF0dGVybnMgb2YgU2VhcmNoCiMjIyBMb2NhbGl0eSBvZiBzYW1wbGluZwoKTGV0J3MgbG9vayBhdCB0aGUgcGF0dGVybnMgaW4gc2VhcmNoIGJlaGF2aW9yLiBGaXJzdCwgbGV0J3MgbG9vayBhdCB0aGUgZGlzdGFuY2UgYmV0d2VlbiBzdWNjZXNzaXZlIGNob2ljZXMuCgpgYGB7cn0KI2NvbXBhcmUgdG8gcmFuZG9tCnNhbXBsZVNpemUgPC0gNDAwMDAwCnJhbmRvbURpc3RhbmNlREYgPC0gZGF0YS5mcmFtZSh4PXNhbXBsZSh4ID0gc2VxKDA6NyksIHNpemUgPSBzYW1wbGVTaXplLCByZXBsYWNlPVRSVUUpLCB5PXNhbXBsZSh4ID0gc2VxKDA6NyksIHNpemUgPSBzYW1wbGVTaXplLCByZXBsYWNlPVRSVUUpLCBlbnZpcm9ubWVudD1jKHJlcCgiUm91Z2giLHNhbXBsZVNpemUvMiksIHJlcCgiU21vb3RoIiwgc2FtcGxlU2l6ZS8yKSksIGNvbnRleHQgPSByZXAoYygnQ29uY2VwdHVhbCcsICdTcGF0aWFsJyksIHNhbXBsZVNpemUvMikpCnJhbmRvbURpc3RhbmNlREYgPC0gcmFuZG9tRGlzdGFuY2VERiAlPiUKICBtdXRhdGUoZGlzdGFuY2UgPSBhYnMoKHggLSBsYWcoeCxkZWZhdWx0ID0gTkEpKSArIGFicyh5IC0gbGFnKHksZGVmYXVsdCA9IE5BKSkgKSkKCgojQWRkIGNsYXNzaWZpY2F0aW9uIG9mIGNob2ljZXMgYXMgc3RheSwgbmVhciwgb3IgZmFyIGRlY2lzaW9ucwpsb2NhbGl0eURGIDwtZGRwbHkoZGYsIH5pZCt0cmlhbCtjb250ZXh0LCAgcGx5cjo6c3VtbWFyaXplLCBhdmdEaXN0YW5jZT1tZWFuKGRpc3RhbmNlLCBuYS5ybT1UKSkKbG9jYWxpdHlERiRjaG9pY2VUeXBlIDwtaWZlbHNlKGxvY2FsaXR5REYkYXZnRGlzdGFuY2U9PTAsICJTdGF5IiwgaWZlbHNlKGxvY2FsaXR5REYkYXZnRGlzdGFuY2U9PTEsICJOZWFyIiwgIkZhciIpKQpsb2NhbGl0eURGJGNob2ljZVR5cGUgPC0gZmFjdG9yKGxvY2FsaXR5REYkY2hvaWNlVHlwZSkKY2hvaWNlUHJvcCA8LSBkZHBseShuYS5vbWl0KGxvY2FsaXR5REYpLC4oaWQsY29udGV4dCksIGZ1bmN0aW9uKHgpIHdpdGgoeCxkYXRhLmZyYW1lKHRhYmxlKGNob2ljZVR5cGUpL2xlbmd0aChjaG9pY2VUeXBlKSwyKSkpCmNob2ljZVByb3AkY2hvaWNlVHlwZSA8LSBmYWN0b3IoY2hvaWNlUHJvcCRjaG9pY2VUeXBlLCBsZXZlbHM9YygiU3RheSIsICJOZWFyIiwgIkZhciIpKQpgYGAKTGV0J3MgZmlyc3QgZG8gYW4gQU5PVkEgaGVyZQoKYGBge3J9CiNUd28gd2F5IG1peGVkIEFOT1ZBOiBjb250ZXh0IGlzIHdpdGhpbiwgZW52aXJvbm1lbnQgaXMgYmV0d2VlbiAKZGQgPC1kZHBseShkZiwgfmlkK2Vudmlyb25tZW50K2NvbnRleHQsICBwbHlyOjpzdW1tYXJpemUsIGF2Z0Rpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVQpKQpkZCRpZCA8LSBmYWN0b3IoZGQkaWQpCnJlcy5hb3YgPC0gYW92KGF2Z0Rpc3RhbmNlIH4gZW52aXJvbm1lbnQqY29udGV4dCArIEVycm9yKGlkL2NvbnRleHQpLCBkYXRhPWRkKQphbm92YV9zdGF0cyhyZXMuYW92KQojIE5vdyBsZXQncyByZXBsaWNhdGUgdmlhIFJvYnVzdCBBTk9WQQpid3RyaW0oYXZnRGlzdGFuY2UgfiBlbnZpcm9ubWVudCpjb250ZXh0LCBpZCA9IGlkLCBkYXRhPWRkLCB0ciA9IDAuMikgI3VzaW5nIDIwJSB0cmltbWVkIG1lYW5zCnNwcGJhKGF2Z0Rpc3RhbmNlIH4gZW52aXJvbm1lbnQqY29udGV4dCwgaWQgPSBpZCwgZGF0YT1kZCkgI01haW4gZml4ZWQgZWZmZWN0CnNwcGJiKGF2Z0Rpc3RhbmNlIH4gZW52aXJvbm1lbnQqY29udGV4dCwgaWQgPSBpZCwgZGF0YT1kZCkgI1dpdGhpbi1zdWJlY3QgZWZmZWN0CiNOb3cgY29tcHV0ZSBCYXllcyBmYWN0b3IKYmYgPSBhbm92YUJGKGF2Z0Rpc3RhbmNlIH4gZW52aXJvbm1lbnQqY29udGV4dCtpZCwgIGRhdGE9ZGQsICB3aGljaFJhbmRvbT0iaWQiKQpiZgoKYGBgCgpMZXQncyBwbG90IHRoZSByZXN1bHRzCmBgYHtyfQoKY29udGV4dExhYmVscyA8LSBjKCdDb25jZXB0dWFsJyA9ICdDb25jZXB0dWFsXG5UYXNrJywgJ1NwYXRpYWwnID0gJ1NwYXRpYWxcblRhc2snLCAiUm91Z2giPSJSb3VnaCIsICJTbW9vdGgiPSJTbW9vdGgiKQpwNGFsdCA8LSBnZ3Bsb3QobmEub21pdChkZiksIGFlcyh4PWRpc3RhbmNlLCBmaWxsID0gY29udGV4dCwgY29sb3IgPSBjb250ZXh0KSkgKyAKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKjIwKSwgcG9zaXRpb24gPSAnZG9kZ2UnLCBiaW53aWR0aD0xLCBjb2xvcj0nYmxhY2snKSsKICBzdGF0X2RlbnNpdHkoZGF0YSA9IHJhbmRvbURpc3RhbmNlREYsIGFlcyh5ID0gLi5kZW5zaXR5Li4qMjApLCBnZW9tPSJsaW5lIixjb2xvcj0nYmxhY2snLCBzaXplID0gLjgsIGJ3ID0gMSkgKwogICNnZW9tX2RlbnNpdHkoZmlsbD1OQSwgc2l6ZSA9IDAuNykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMUI5RTc3IiwgIiNEOTVGMDIiLCAiQmxhY2siKSwgbmFtZT0iIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMUI5RTc3IiwgIiNEOTVGMDIiLCAiQmxhY2siKSwgbmFtZT0iIikgKwogIHlsYWIoIkNob2ljZXMgUGVyIFJvdW5kIikgKwogIHhsYWIoIkRpc3RhbmNlIEJldHdlZW4gQ2hvaWNlcyIpICsKICAjeGxpbSgwLDYpKwogIGZhY2V0X2dyaWQoY29udGV4dH5lbnZpcm9ubWVudCwgIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoY29udGV4dExhYmVscykpKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MobiA9IDUpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwLCBieSA9IDIpKSsKICAjZ2d0aXRsZSgiTG9jYWxpdHkgb2YgU2FtcGxpbmciKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJywgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5rZXk9ZWxlbWVudF9yZWN0KGNvbG9yPU5BKSkKcDRhbHQKYGBgCgpMZXQncyB0cnkgYSBkaWZmZXJlbnQgdmVyc2lvbiB3aGVyZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0YXNrIGFyZSBtb3JlIHNhbGllbnQKYGBge3J9Cgpjb250ZXh0TGFiZWxzIDwtIGMoJ0NvbmNlcHR1YWwnID0gJ0NvbmNlcHR1YWxcblRhc2snLCAnU3BhdGlhbCcgPSAnU3BhdGlhbFxuVGFzaycsICJSb3VnaCI9IlJvdWdoIiwgIlNtb290aCI9IlNtb290aCIpCmFubmRmPC1kYXRhLmZyYW1lKGRpc3RhbmNlID0gTkEsY29udGV4dCA9ICBOQSxlbnZpcm9ubWVudCA9IGZhY3RvcigiU21vb3RoIiwgbGV2ZWxzID0gYygiUm91Z2giLCAiU21vb3RoIikpLCB0ZXh0ID0gJ1JhbmRvbScsIGNvbG9yID0gJ2JsYWNrJykgI2ZvciBhbm5vdGF0aW9uCnA0YWx0IDwtIGdncGxvdChuYS5vbWl0KGRmKSwgYWVzKHg9ZGlzdGFuY2UsIGZpbGwgPSBjb250ZXh0LCBjb2xvciA9IGNvbnRleHQpKSArIAogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4qMjApLCBwb3NpdGlvbiA9ICdpZGVudGl0eScsIGJpbndpZHRoPTEsIGFscGhhID0gMC40KSsKICBzdGF0X2RlbnNpdHkoZGF0YSA9IHN1YnNldChyYW5kb21EaXN0YW5jZURGLCBjb250ZXh0ID09ICdDb25jZXB0dWFsJyksIGFlcyh5ID0gLi5kZW5zaXR5Li4qMjApLCBnZW9tPSJsaW5lIixjb2xvcj0nYmxhY2snLCBzaXplID0gLjgsIGJ3ID0gMSkgKwogICNnZW9tX2RlbnNpdHkoZmlsbD1OQSwgc2l6ZSA9IDAuNykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMUI5RTc3IiwgIiNEOTVGMDIiLCAiQmxhY2siKSwgbmFtZT0iVGFzayIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzFCOUU3NyIsICIjRDk1RjAyIiwgIkJsYWNrIiksIG5hbWU9IlRhc2siKSArCiAgeWxhYigiQ2hvaWNlcyBQZXIgUm91bmQiKSArCiAgeGxhYigiRGlzdGFuY2UgQmV0d2VlbiBDaG9pY2VzIikgKwogICN4bGltKDAsNikrCiAgZmFjZXRfZ3JpZCh+ZW52aXJvbm1lbnQsICBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKGNvbnRleHRMYWJlbHMpKSsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSA1KSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMCwgYnkgPSAyKSkrCiAgI2dndGl0bGUoIkxvY2FsaXR5IG9mIFNhbXBsaW5nIikgKwogICNnZW9tX3RleHQoZGF0YSA9IGFubmRmLCB4ID0gMTAuNSwgeSA9IDUsIGxhYmVsID0gIlJhbmRvbSIsIGNvbG9yID0gJ2JsYWNrJywgc2l6ZSA9IDMuNSkrCiAgI2dlb21fc2VnbWVudChkYXRhID0gYW5uZGYsICB4ID0gOSwgeGVuZCA9IDEwLCB5ID0gNSwgeWVuZCA9IDUsY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDEuMikrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMSwxKSwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsMSksIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQua2V5PWVsZW1lbnRfcmVjdChjb2xvcj1OQSkpCnA0YWx0CmBgYAoKUGFydGljaXBhbnRzIHNlYXJjaGVkIG92ZXIgbGFyZ2VyIGRpc3RhbmNlcyBpbiB0aGUgY29uY2VwdHVhbCB0YXNrIHRoYW4gdGhlIHNwYXRpYWwgdGFzayAoJHQoMTI4KT0tMy43JCwgJHA8LjAwMSQsICRkPTAuMyQsICRCRj01OSQpLiBUaGVyZSB3ZXJlIG5vIGRpZmZlcmVuY2VzIGFjcm9zcyBlbnZpcm9ubWVudHMgKCR0KDEyNyk9LTAuMyQsICRwPS43MjckLCAkZD0wLjA2JCwgJEJGPS4yMCQpLiBOb3RlIHRoYXQgZWFjaCB0cmlhbCBiZWdhbiBvbiBhIHJhbmRvbSBzZWxlY3RlZCBzdGltdWxpLiBTbyBzZWFyY2hpbmcgY2xvc2UgdG8gdGhlIHByZXZpb3VzIHNlbGVjdGlvbiBpcyBub3QgZHVlIHRvIGEgbGFjayBvZiBlZmZvcnQuICgkdCgxMjgpPS0xNi4yJCwgJHA8LjAwMSQsICRkPTEuNCQsICRCRj4xMDAkKQoKYGBge3IgZXZhbD1GLCBlY2hvPVR9CiNTdGF0aXN0aWNhbCB0ZXN0cyByZXBvcnRlZCBhYm92ZQpsb2NhbGl0eURGIDwtIGRkcGx5KGRmLCB+aWQrY29udGV4dCxwbHlyOjpzdW1tYXJpemUsIGF2Z0Rpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVQpKQp0dGVzdFByZXR0eShzdWJzZXQobG9jYWxpdHlERiwgY29udGV4dCA9PSAnU3BhdGlhbCcpJGF2Z0Rpc3RhbmNlLCBzdWJzZXQobG9jYWxpdHlERiwgY29udGV4dCA9PSAnQ29uY2VwdHVhbCcpJGF2Z0Rpc3RhbmNlLCB2YXIuZXF1YWw9VCwgcGFpcmVkPVQpCgpsb2NhbGl0eURGIDwtIGRkcGx5KGRmLCB+aWQrZW52aXJvbm1lbnQscGx5cjo6c3VtbWFyaXplLCBhdmdEaXN0YW5jZT1tZWFuKGRpc3RhbmNlLCBuYS5ybT1UKSkKdHRlc3RQcmV0dHkoc3Vic2V0KGxvY2FsaXR5REYsIGVudmlyb25tZW50ID09ICdTbW9vdGgnKSRhdmdEaXN0YW5jZSwgc3Vic2V0KGxvY2FsaXR5REYsIGVudmlyb25tZW50ID09ICdSb3VnaCcpJGF2Z0Rpc3RhbmNlLCB2YXIuZXF1YWw9VCkKCmxvY2FsaXR5REYgPC0gZGRwbHkoIGRmLCB+aWQsIHBseXI6OnN1bW1hcml6ZSwgYXZnRGlzdGFuY2U9bWVhbihkaXN0YW5jZSwgbmEucm09VCkpCnR0ZXN0UHJldHR5KG5hLm9taXQobG9jYWxpdHlERiRhdmdEaXN0YW5jZSksIG11ID0gbWVhbihyYW5kb21EaXN0YW5jZURGJGRpc3RhbmNlLCBuYS5ybT1UKSkKYGBgCgoKTm93IGxldCdzIGNsYXNzaWZ5IHRoZXNlIGNob2ljZXMgYXMgZWl0aGVyIGBTdGF5YCAoZGlzdGFuY2UgPSAwKSwgYE5lYXJgIChkaXN0YW5jZSA9IDEpLCBvciBgRmFyYCAoZGlzdGFuY2UgPjEpLgpgYGB7cn0KI2Nob2ljZSBwcm9wCmxvY2FsaXR5REYgPC1kZHBseShkZiwgfmlkK3RyaWFsK2NvbnRleHQsICBwbHlyOjpzdW1tYXJpemUsIGF2Z0Rpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVQpKQpsb2NhbGl0eURGJGRpc3RhbmNlIDwtbG9jYWxpdHlERiRhdmdEaXN0YW5jZQpyYW5kb21EaXN0YW5jZURGJGlkIDwtIDAKcmFuZG9tRGlzdGFuY2VERiRjb250ZXh0IDwtICdSYW5kb20nCmxvY2FsaXR5REYgPC0gcmJpbmQobG9jYWxpdHlERlssYyggImNvbnRleHQiLCAiZGlzdGFuY2UiLCAnaWQnKV0sIHJhbmRvbURpc3RhbmNlREZbLGMoICJjb250ZXh0IiwgImRpc3RhbmNlIiwgJ2lkJyldKQoKbG9jYWxpdHlERiRjaG9pY2VUeXBlIDwtaWZlbHNlKGxvY2FsaXR5REYkZGlzdGFuY2U9PTAsICJTdGF5IiwgaWZlbHNlKGxvY2FsaXR5REYkZGlzdGFuY2U9PTEsICJOZWFyIiwgIkZhciIpKQpsb2NhbGl0eURGJGNob2ljZVR5cGUgPC0gZmFjdG9yKGxvY2FsaXR5REYkY2hvaWNlVHlwZSkKCmNob2ljZVByb3AgPC0gZGRwbHkobmEub21pdChsb2NhbGl0eURGKSwuKGlkLGNvbnRleHQpLCAKICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSB3aXRoKHgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHRhYmxlKGNob2ljZVR5cGUpL2xlbmd0aChjaG9pY2VUeXBlKSwyKSkpCgpjaG9pY2VQcm9wJGNob2ljZVR5cGUgPC0gZmFjdG9yKGNob2ljZVByb3AkY2hvaWNlVHlwZSwgbGV2ZWxzPWMoIlN0YXkiLCAiTmVhciIsICJGYXIiKSkKCgpwNCA8LSBnZ3Bsb3QobmEub21pdChjaG9pY2VQcm9wKSwgYWVzKHg9Y2hvaWNlVHlwZSwgeSA9IEZyZXEqMjAsIGZpbGw9Y29udGV4dCwgY29sb3IgPSBjb250ZXh0KSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbixnZW9tPSdiYXInLCBwb3NpdGlvbj0nZG9kZ2UnLCBjb2xvcj0nYmxhY2snKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbSA9ICJlcnJvcmJhciIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkwKSwgd2lkdGggPSAwLjIsIGNvbG9yPSdibGFjaycgKSArCiAgI3NjYWxlX3lfY29udGludW91cyhsYWJlbHM9cGVyY2VudCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiMxQjlFNzciLCAiI0Q5NUYwMiIsICJCbGFjayIpLCBuYW1lPSIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMUI5RTc3IiwgIiNEOTVGMDIiLCAiQmxhY2siKSwgbmFtZT0iIikgKwogICNzY2FsZV9maWxsX3JpY2thbmRtb3J0eSgpKwogIHlsYWIoJ0Nob2ljZXMgUGVyIFJvdW5kIMKxU0UnKSsKICB4bGFiKCJDaG9pY2UgVHlwZSIpKwogICNmYWNldF9ncmlkKH5jb250ZXh0T3JkZXIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0gYygwLjA1LCAxKSwgbGVnZW5kLmp1c3RpZmljYXRpb249YygwLDEpLCBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKQpwNAoKYGBgCgpUaGlzIHNlZW1zIHRvIHBhaW50IHRoZSBzYW1lIHBpY3R1cmUgYXMgdGhlIGRpc3RhbmNlIGhpc3RvZ3JhbXMgYmVmb3JlLiBQYXJ0aWNpcGFudHMgbWFkZSBtb3JlIHN0YXkgY2hvaWNlcyBpbiB0aGUgc3BhdGlhbCB0YXNrIChgciB0dGVzdFByZXR0eShzdWJzZXQoY2hvaWNlUHJvcCwgY29udGV4dD09IkNvbmNlcHR1YWwiICYgY2hvaWNlVHlwZSA9PSJTdGF5IikkRnJlcSwgc3Vic2V0KGNob2ljZVByb3AsIGNvbnRleHQ9PSJTcGF0aWFsIiAmIGNob2ljZVR5cGUgPT0iU3RheSIpJEZyZXEsIHZhci5lcXVhbCA9IFQsIHBhaXJlZCA9IFQpYCkgYW5kIG1vcmUgZmFyIGNob2ljZXMgaW4gdGhlIGNvbmNlcHR1YWwgdGFzayAoYHIgdHRlc3RQcmV0dHkoc3Vic2V0KGNob2ljZVByb3AsIGNvbnRleHQ9PSJDb25jZXB0dWFsIiAmIGNob2ljZVR5cGUgPT0iRmFyIikkRnJlcSwgc3Vic2V0KGNob2ljZVByb3AsIGNvbnRleHQ9PSJTcGF0aWFsIiAmIGNob2ljZVR5cGUgPT0iRmFyIikkRnJlcSwgdmFyLmVxdWFsID0gVCwgcGFpcmVkID0gVClgKS4gVGhlcmUgd2VyZSBubyBkaWZmZXJlbmNlcyBpbiBuZWFyIGNob2ljZXMgKGByIHR0ZXN0UHJldHR5KHN1YnNldChjaG9pY2VQcm9wLCBjb250ZXh0PT0iQ29uY2VwdHVhbCIgJiBjaG9pY2VUeXBlID09Ik5lYXIiKSRGcmVxLCBzdWJzZXQoY2hvaWNlUHJvcCwgY29udGV4dD09IlNwYXRpYWwiICYgY2hvaWNlVHlwZSA9PSJOZWFyIikkRnJlcSwgdmFyLmVxdWFsID0gVCwgcGFpcmVkID0gVClgKS4KCiMjIyBTZWFyY2ggVHJhamVjdG9yaWVzCgpXZSBoYXZlIHRoaXMgcmVhbGx5IHJpY2ggZGF0YSBhYm91dCBob3cgcGFydGljaXBhbnRzIG5hdmlnYXRlZCB0aGUgc2VhcmNoIHNwYWNlLiBMZXQncyBmaXJzdCBsb29rIGF0IHRoZSBudW1iZXIgb2Ygc3RlcHMgcGFydGljaXBhbnRzIHRvb2sgYmVmb3JlIG1ha2luZyBhIHNlbGVjdGlvbgpgYGB7cn0KZGYkc3RlcHMgPC0gc2FwcGx5KGRmJHRyYWplY3RvcmllcywgZnVuY3Rpb24oaSkgbGVuZ3RoKGZyb21KU09OKGFzLmNoYXJhY3RlcihpKSkpKQp0cmFqREYgPC0gZGYlPiUgZ3JvdXBfYnkoaWQsY29udGV4dCkgJT4lIGRwbHlyOjpzdW1tYXJpemUoYXZnU3RlcHM9bWVhbihzdGVwcywgbmEucm09VCkpCnRyYWpDb250ZXh0REYgPC0gZGYlPiUgZ3JvdXBfYnkoaWQsY29udGV4dCkgJT4lIGRwbHlyOjpzdW1tYXJpemUoYXZnU3RlcHM9bWVhbihzdGVwcywgbmEucm09VCkpCnRyYUVudmpERiA8LSBkZiU+JSBncm91cF9ieShpZCxlbnZpcm9ubWVudCkgJT4lIGRwbHlyOjpzdW1tYXJpemUoYXZnU3RlcHM9bWVhbihzdGVwcywgbmEucm09VCkpCgpsZXZlbHMoZGYkY29udGV4dE9yZGVyKTwtIGMoIlNwYXRpYWwgRmlyc3QiLCAiQ29uY2VwdHVhbCBGaXJzdCIpCiNjb21wYXJpbmcgY29udGV4dApnZ3Bsb3QoZGYsIGFlcyh4ID0gY29udGV4dCwgeSA9IHN0ZXBzLCBmaWxsID0gY29udGV4dCkpKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAiYmFyIiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvcj0nYmxhY2snKSArIAogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb20gPSAiZXJyb3JiYXIiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45MCksIHdpZHRoID0gMC4yLCBjb2xvciA9ICdibGFjaycgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdyaWdodCcsIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQua2V5PWVsZW1lbnRfcmVjdChjb2xvcj1OQSksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE2LCAgZmFtaWx5PSJzYW5zIikpKwogICNjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsOCkpICsKICB4bGFiKCIiKSsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbmFtZT0iIikgKwogIGZhY2V0X2dyaWQofmNvbnRleHRPcmRlcikrCiAgeWxhYigiTWVhbiBOdW1iZXIgb2YgU3RlcHMgXHUwMEIxU0UiKQoKCm1lZGlhbnMgPC0gZGYlPiUgZ3JvdXBfYnkoZW52aXJvbm1lbnQsY29udGV4dCkgJT4lIGRwbHlyOjpzdW1tYXJpemUoc3RlcHM9bWVhbihzdGVwcywgbmEucm09VCkpCmNvbnRleHRMYWJlbHMgPC0gYygnQ29uY2VwdHVhbCcgPSAnQ29uY2VwdHVhbFxuVGFzaycsICdTcGF0aWFsJyA9ICdTcGF0aWFsXG5UYXNrJywgIlJvdWdoIj0iUm91Z2giLCAiU21vb3RoIj0iU21vb3RoIikKdHJhamVjdG9yeXBsb3QgPC0gZ2dwbG90KG5hLm9taXQoZGYpLCBhZXMoeD1zdGVwcywgZmlsbCA9IGNvbnRleHQsIGNvbG9yID0gY29udGV4dCkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLioyMCksIHBvc2l0aW9uID0gJ2RvZGdlJywgYmlud2lkdGg9MSwgY29sb3I9J2JsYWNrJykrCiAgI3N0YXRfZGVuc2l0eShkYXRhID0gYXMuZGF0YS5mcmFtZShyYW5kb21ERiksIGFlcyh2YWx1ZSksZ2VvbT0ibGluZSIsY29sb3I9J2JsYWNrJywgc2l6ZSA9IC44LCBsaW5ldHlwZT0nZGFzaGVkJykgKwogICNnZW9tX2RlbnNpdHkoZmlsbD1OQSwgc2l6ZSA9IDAuNykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMUI5RTc3IiwgIiNEOTVGMDIiLCAiQmxhY2siKSwgbmFtZT0iIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjMUI5RTc3IiwgIiNEOTVGMDIiLCAiQmxhY2siKSwgbmFtZT0iIikgKwogIGdlb21fdmxpbmUoZGF0YSA9IG1lZGlhbnMsIGFlcyh4aW50ZXJjZXB0ID0gc3RlcHMpLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBzaXplID0uNykrCiAgeWxhYigiQ2hvaWNlcyBQZXIgUm91bmQiKSArCiAgeGxhYigiVHJhamVjdG9yeSBMZW5ndGgiKSArCiAgI3hsaW0oMCw2KSsKICBmYWNldF9ncmlkKGNvbnRleHR+ZW52aXJvbm1lbnQsIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoY29udGV4dExhYmVscykpKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MobiA9IDUpLCBsaW1pdHMgPSBjKDAsMjApKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDMsIGJ5ID0gMSkpKwogICNnZ3RpdGxlKCJMb2NhbGl0eSBvZiBTYW1wbGluZyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnLCBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKQp0cmFqZWN0b3J5cGxvdAoKYGBgClBhcnRpY2lwYW50cyBoYWQgbG9uZ2VyIHRyYWplY3RvcmllcyBpbiB0aGUgY29udGV4dHVhbCB0YXNrICgkdCgxMjgpPS0xMC43JCwgJHA8LjAwMSQsICRkPTEuMCQsICRCRj4xMDAkKSwgYWx0aG91Z2ggdGhlcmUgd2VyZSBubyBkaWZmZXJlbmNlcyBhY3Jvc3MgZW52aXJvbm1lbnRzICgkdCgxMjcpPTEuMyQsICRwPS4yMTMkLCAkZD0wLjIkLCAkQkY9LjM4JCkuIAoKCmBgYHtyIG1lc3NhZ2U9Rn0KdHRlc3RQcmV0dHkoc3Vic2V0KHRyYWpDb250ZXh0REYsIGNvbnRleHQgPT0gJ1NwYXRpYWwnKSRhdmdTdGVwcywgc3Vic2V0KHRyYWpDb250ZXh0REYsIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRhdmdTdGVwcywgdmFyLmVxdWFsPVQsIHBhaXJlZD1UKQp0dGVzdFByZXR0eShzdWJzZXQodHJhRW52akRGLCBlbnZpcm9ubWVudCA9PSAnU21vb3RoJykkYXZnU3RlcHMsIHN1YnNldCh0cmFFbnZqREYsIGVudmlyb25tZW50ID09ICdSb3VnaCcpJGF2Z1N0ZXBzLCB2YXIuZXF1YWw9VCkKYGBgCiMjIyBBdHRlbnRpb25hbCBCaWFzZXMKCkxldCdzIGFsc28gbG9vayBhdCB0aGUgdHJhamVjdG9yaWVzIGRlY29tcG9zZWQgaW50byB0aGUgdmVydGljYWwvc3RyaXBlIGZyZXF1ZW5jeSBkaW1lbnNpb24gdnMuIGhvcml6b250YWwvdGlsdCBkaW1lbnNpb24uIFRoZSBmaWd1cmUgYmVsb3cgc2hvd3MgdGhlIHByb3BvcnRpb24gb2YgcGFydGljaXBhbnQgaW5wdXRzIGNvcnJlc3BvbmRpbmcgdG8gZWFjaCBkaW1lbnNpb24sIHdoZXJlIHdlIHNlZSBhbiBoaWdoZXIgcHJvcG9ydGlvbiBvZiBpbnB1dHMgZ2l2ZW4gdG8gdGhlIHZlcnRpY2FsL3N0cmlwZSBmcmVxdWVuY3kgZGltZW5zaW9uIGluIGJvdGggdGFza3MsIHJlbGF0aXZlIHRvIHRoZSBob3Jpem9udGFsL3RpbHQgZGltZW5zaW9uLgpgYGB7cn0KI2NvbXBpbGUgdG90YWwgYnV0dG9uIHByZXNzZXNzIGZvciBlYWNoIGRpbWVuc2lvbgpkZiR0cmFqTGVmdCA8LSBzYXBwbHkoZGYkdHJhamVjdG9yaWVzLCBmdW5jdGlvbihpKSBzdW0oZnJvbUpTT04oYXMuY2hhcmFjdGVyKGkpKSA9PSAzNykpCmRmJHRyYWpVcCA8LSBzYXBwbHkoZGYkdHJhamVjdG9yaWVzLCBmdW5jdGlvbihpKSBzdW0oZnJvbUpTT04oYXMuY2hhcmFjdGVyKGkpKSA9PSAzOCkpCmRmJHRyYWpSaWdodCA8LSBzYXBwbHkoZGYkdHJhamVjdG9yaWVzLCBmdW5jdGlvbihpKSBzdW0oZnJvbUpTT04oYXMuY2hhcmFjdGVyKGkpKSA9PSAzOSkpCmRmJHRyYWpEb3duIDwtIHNhcHBseShkZiR0cmFqZWN0b3JpZXMsIGZ1bmN0aW9uKGkpIHN1bShmcm9tSlNPTihhcy5jaGFyYWN0ZXIoaSkpID09IDQwKSkKICAgICAgICAgICAgICAgICAgICAgIAp0cmFqRGlyREYgPC0gZGRwbHkoZGYsIH5pZCtjb250ZXh0K2Vudmlyb25tZW50LCBwbHlyOjpzdW1tYXJpemUsIGhvcml6b250YWwgPSAoc3VtKHRyYWpMZWZ0KStzdW0odHJhalJpZ2h0KSkvc3VtKHN0ZXBzKSwgdmVydGljYWwgPSAoc3VtKHRyYWpVcCkrc3VtKHRyYWpEb3duKSkvc3VtKHN0ZXBzKSkgI2NvbXB1dGUgYXZlcmFnZSBwZXIgcGFydGljaXBhbnQgcGVyIHRyaWFsCnRyYWpEaXJERiA8LSB0cmFqRGlyREYgICU+JSBnYXRoZXIoZGlyZWN0aW9uLCBwLCBob3Jpem9udGFsOnZlcnRpY2FsLCBmYWN0b3Jfa2V5PVRSVUUpICN3aWRlIHRvIGxvbmcKdHJhakRpckRGJGRpcmVjdGlvbiA8LSBmYWN0b3IodHJhakRpckRGJGRpcmVjdGlvbikKbGV2ZWxzKHRyYWpEaXJERiRkaXJlY3Rpb24pPC0gYygnSG9yaXpvbnRhbC9cblJvdGF0aW9uJywgJ1ZlcnRpY2FsL1xuU3RyaXBlcycpCnRyYWpEaXJERiRpZCA8LSBmYWN0b3IodHJhakRpckRGJGlkKQoKCiNwbG90CmlucHV0ZGlyIDwtIGdncGxvdCh0cmFqRGlyREYsIGFlcyh4ID0gZGlyZWN0aW9uLCB5ID0gcCwgZmlsbCA9IGNvbnRleHQpKSsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImJhciIsIHBvc2l0aW9uID0gImRvZGdlIiwgY29sb3I9J2JsYWNrJykgKyAKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsIGdlb20gPSAiZXJyb3JiYXIiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45MCksIHdpZHRoID0gMC4yLCBjb2xvciA9ICdibGFjaycgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdyaWdodCcsIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQua2V5PWVsZW1lbnRfcmVjdChjb2xvcj1OQSksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkrCiAgI2Nvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw4KSkgKwogIHhsYWIoIklucHV0IikrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siKSArCiAgZmFjZXRfZ3JpZCh+ZW52aXJvbm1lbnQpKwogIHlsYWIoIlByb3BvcnRpb24gb2YgSW5wdXRzIFx1MDBCMSA5NSUgQ0kiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ3RvcCcpCmlucHV0ZGlyCmBgYApXZSBmb3JtYWxseSBkZWZpbmUgdGhlIGRpZmZlcmVuY2UgaW4gYXR0ZW50aW9uICRcRGVsdGFfe1x0ZXh0cm17ZGltfX0gPSBQKFx0ZXh0cm17dmVydGljYWwvc3RyaXBlIGZyZXF1ZW5jeX0pIC0gUChcdGV4dHJte2hvcml6b250YWwvdGlsdH0pJCwgd2hlcmUgcG9zaXRpdmUgdmFsdWVzIGluZGljYXRlIGEgc3Ryb25nZXIgYmlhcyB0b3dhcmRzIHRoZSB2ZXJ0aWNhbC9zdHJpcGUgZnJlcXVlbmN5IGRpbWVuc2lvbi4gUnVubmluZyBhIHR3by13YXkgbWl4ZWQgQU5PVkEgcmV2ZWFscyB0aGF0IGF0dGVudGlvbmFsIGJpYXMgd2FzIGluZmx1ZW5jZWQgYnkgdGhlIGludGVyYWN0aW9uIG9mIHRhc2sgb3JkZXIgYW5kIHRhc2sgKCRGKDEsMTI3KSA9IDguMSQsICAkcD0uMDA1JCwgJFxldGFeMj0uMDIkLCAkQkY+MTAwJCkuIAoKYGBge3J9CiNhZGQgdGFzayBvcmRlciBpbnRvIHRyYWpEaWZERgp0cmFqRGlyREYkRmlyc3RUYXNrIDwtIGRmW21hdGNoKHRyYWpEaXJERiRpZCwgZGYkaWQpLCJGaXJzdFRhc2siXQpkaWZmREYgPC0gZGRwbHkodHJhakRpckRGLCB+aWQrZW52aXJvbm1lbnQrY29udGV4dCtGaXJzdFRhc2ssIHBseXI6OnN1bW1hcml6ZSwgcGRpZmYgPSBkaWZmKHApKSAjY2FsY3VsYXRlIHRoZSBkaWZmZXJlbmNlIGluIHByb3BvcnRpb24gb2Yga2V5IHByZXNzZXMgb3ZlciBjb250ZXh0cyAocG9zaXRpdmUgaXMgbW9yZSB2ZXJ0aWNhbCwgd2hpbGUgbmVnYXRpdmUgaXMgbW9yZSBob3Jpem9udGFsICkKCiNBbm92YQpyZXMuYW92IDwtIGFvdihwIH4gY29udGV4dCpGaXJzdFRhc2sgKyBFcnJvcihpZC9jb250ZXh0KSwgZGF0YSA9ICBzdWJzZXQodHJhakRpckRGLCBkaXJlY3Rpb24gPT0nSG9yaXpvbnRhbC9cblJvdGF0aW9uJykpCmFub3ZhX3N0YXRzKHJlcy5hb3YpCiNSZXBsaWNhdGlvbiB3aXRoIHJvYnVzdCBBTk9WQQpid3RyaW0ocCB+IGNvbnRleHQqRmlyc3RUYXNrLCBpZCA9IGlkLCBkYXRhPXN1YnNldCh0cmFqRGlyREYsIGRpcmVjdGlvbiA9PSdIb3Jpem9udGFsL1xuUm90YXRpb24nKSwgdHIgPSAwLjIpICN1c2luZyAyMCUgdHJpbW1lZCBtZWFucwojQmF5ZXMgZmFjdG9yIG9mIEFOT1ZBCmludmlzaWJsZShiZiA8LSBhbm92YUJGKHAgfiAgY29udGV4dCpGaXJzdFRhc2sgLCAgZGF0YT1zdWJzZXQodHJhakRpckRGLCBkaXJlY3Rpb24gPT0nSG9yaXpvbnRhbC9cblJvdGF0aW9uJyksICB3aGljaFJhbmRvbT0iaWQiKSkKYmYKCmBgYAoKYGBge3J9CnBBdHRlbnRpb25UYXNrT3JkZXIgPC0gZ2dwbG90KGRpZmZERiwgYWVzKHggPSBjb250ZXh0LCB5ID0gcGRpZmYsIGZpbGwgPSBjb250ZXh0KSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbT0nYmFyJywgY29sb3I9J2JsYWNrJykrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ib290LCBnZW9tPSdlcnJvcmJhcicsIGNvbG9yID0gJ2JsYWNrJywgd2lkdGggPSAwLjIpKwogIGZhY2V0X2dyaWQofkZpcnN0VGFzaykrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdub25lJywgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5rZXk9ZWxlbWVudF9yZWN0KGNvbG9yPU5BKSwgbGVnZW5kLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpKSsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDgpKSArCiAgeGxhYigiIikrCiAgeWxhYihleHByZXNzaW9uKCBEZWx0YVtkaW1dKSkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siKSAKcEF0dGVudGlvblRhc2tPcmRlcgpgYGAKIApXaGlsZSBwYXJ0aWNpcGFudHMgd2VyZSBtb3JlIGJpYXNlZCB0b3dhcmRzIHRoZSB2ZXJ0aWNhbC9zdHJpcGUgZnJlcXVlbmN5IGRpbWVuc2lvbiBpbiB0aGUgY29uY2VwdHVhbCB0YXNrIHdoZW4gdGhlIGNvbmNlcHR1YWwgdGFzayB3YXMgcGVyZm9ybWVkIGZpcnN0ICgkdCg2Nik9LTYuMCQsICRwPC4wMDEkLCAkZD0wLjckLCAkQkY+MTAwJCksIHRoZXNlIGRpZmZlcmVuY2VzIGRpc2FwcGVhcmVkIHdoZW4gdGhlIHNwYXRpYWwgdGFzayB3YXMgcGVyZm9ybWVkIGZpcnN0ICgkdCg2MSk9LTEuNiQsICRwPS4xMTgkLCAkZD0wLjIkLCAkQkY9LjQ1JCkuIApgYGB7ciBldmFsPUYsIGVjaG89VH0KdHRlc3RQcmV0dHkoc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdDb25jZXB0dWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ1NwYXRpYWwnKSRwZGlmZi0gc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdDb25jZXB0dWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRwZGlmZiwgbXU9MCkKdHRlc3RQcmV0dHkoc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdTcGF0aWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ1NwYXRpYWwnKSRwZGlmZi0gc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdTcGF0aWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRwZGlmZiwgbXU9MCkKYGBgCgpEb2VzIHVuZXF1YWwgcHJlZmVyZW5jZSBmb3Igb25lIG9mIHRoZSBmZWF0dXJlIGRpbWVuc2lvbnMgaW5mbHVlbmNlIHBlcmZvcm1hbmNlPyBUaGUgcmVzdWx0cyBhcmUgcHJlc2VudGVkIGluIHRoZSBmaWd1cmUgYmVsb3csIHdoZXJlIGVhY2ggcGFpciBvZiBkb3RzIGlzIGEgc2luZ2xlIHBhcnRpY2lwYW50LCBhbmQgdGhlIGNvbm5lY3RpbmcgbGluZSBzaG93cyB0aGUgY2hhbmdlIGluIHNjb3JlIGFuZCBjaGFuZ2UgaW4gYXR0ZW50aW9uYWwgYmlhcyAkXERlbHRhX3tcdGV4dHJte2RpbX19JCBhY3Jvc3MgdGFza3MuCmBgYHtyfQpwZXJmREY8LSBkZHBseShkZiwgfmlkK2Vudmlyb25tZW50K2NvbnRleHQrRmlyc3RUYXNrLCBwbHlyOjpzdW1tYXJpemUsIHNjb3JlID0gbWVhbih6KSkKZGlmZkRGJHNjb3JlIDwtIHBlcmZERiRzY29yZSAjdGFzayBzcGVjaWZpYyBzY29yZQoKcFNjb3JlQXR0ZW50aW9uIDwtIGdncGxvdChkaWZmREYsIGFlcyh4ID0gcGRpZmYsIHkgPSBzY29yZSwgY29sb3IgPWNvbnRleHQpKSsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuOCkgKyAKICBnZW9tX2xpbmUoYWVzKGdyb3VwPWlkKSwgY29sb3IgPSAnYmxhY2snLCBhbHBoYSA9IDAuMSkrCiAgZmFjZXRfZ3JpZCh+Rmlyc3RUYXNrKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siKSArCiAgI2dlb21fc21vb3RoKG1ldGhvZCA9ICdsbScpKwogeGxhYihleHByZXNzaW9uKCBEZWx0YVtkaW1dKSkrCiAgeWxhYignTWVhbiBTY29yZScpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ndG9wJywgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5rZXk9ZWxlbWVudF9yZWN0KGNvbG9yPU5BKSkKcFNjb3JlQXR0ZW50aW9uCmBgYAoKV2UgZmluZCBhIG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNjb3JlIGFuZCBhdHRlbnRpb24gZm9yIHRoZSBjb25jZXB0dWFsIHRhc2sgb25seSBpbiB0aGUgY29uY2VwdHVhbCBmaXJzdCBvcmRlciAoJHJfe1x0YXV9PS0uMzEkLCAkcDwuMDAxJCwgJEJGPjEwMCQpLCBidXQgbm90IGluIHRoZSBzcGF0aWFsIGZpcnN0IG9yZGVyICgkcl97XHRhdX09LS4wNyQsICRwPS4zOTIkLCAkQkY9LjI0JCkuIFRoZXJlIHdlcmUgbm8gcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHNjb3JlIGFuZCBhdHRlbnRpb24gaW4gdGhlIHNwYXRpYWwgdGFzayBpbiBlaXRoZXIgb3JkZXIgKHNwYXRpYWwgZmlyc3Q6ICRyX3tcdGF1fT0uMDMkLCAkcD0uNzM4JCwgJEJGPS4xNyQ7IGNvbmNlcHR1YWwgZmlyc3Q6ICRyX3tcdGF1fT0tLjAzJCwgJHA9Ljc1MCQsICRCRj0uMTckKS4gVGh1cywgc3Ryb25nIGF0dGVudGlvbmFsIGJpYXNlcyBwcmVkaWN0ZWQgbG93ZXIgc2NvcmUsIGJ1dCBvbmx5IGluIHRoZSBjb25jZXB0dWFsIGZpcnN0IHRhc2sgb3JkZXIuCgpgYGB7ciBldmFsPUYsIGVjaG89VH0KI3NwYXRpYWwgZmlyc3QKY29yVGVzdFByZXR0eShzdWJzZXQoZGlmZkRGLCBGaXJzdFRhc2sgPT0gJ1NwYXRpYWwgRmlyc3QnICYgY29udGV4dCA9PSAnU3BhdGlhbCcpJHBkaWZmLCBzdWJzZXQoZGlmZkRGLCBGaXJzdFRhc2sgPT0gJ1NwYXRpYWwgRmlyc3QnICYgY29udGV4dCA9PSAnU3BhdGlhbCcpJHNjb3JlLCBtZXRob2QgPSAna2VuZGFsbCcpCmNvclRlc3RQcmV0dHkoc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdTcGF0aWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRwZGlmZiwgc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdTcGF0aWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRzY29yZSwgbWV0aG9kID0gJ2tlbmRhbGwnKQoKY29yVGVzdFByZXR0eShzdWJzZXQoZGlmZkRGLCBGaXJzdFRhc2sgPT0gJ0NvbmNlcHR1YWwgRmlyc3QnICYgY29udGV4dCA9PSAnU3BhdGlhbCcpJHBkaWZmLCBzdWJzZXQoZGlmZkRGLCBGaXJzdFRhc2sgPT0gJ0NvbmNlcHR1YWwgRmlyc3QnICYgY29udGV4dCA9PSAnU3BhdGlhbCcpJHNjb3JlLCBtZXRob2QgPSAna2VuZGFsbCcpCmNvclRlc3RQcmV0dHkoc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdDb25jZXB0dWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRwZGlmZiwgc3Vic2V0KGRpZmZERiwgRmlyc3RUYXNrID09ICdDb25jZXB0dWFsIEZpcnN0JyAmIGNvbnRleHQgPT0gJ0NvbmNlcHR1YWwnKSRzY29yZSwgbWV0aG9kID0gJ2tlbmRhbGwnKQpgYGAKV2Ugbm93IGxvb2sgYXQgZGlmZmVyZW5jZXMgaW4gYXR0ZW50aW9uYWwgYmlhc2VzIGJldHdlZW4gdGFza3MuIFdlIGRlZmluZSAkXERlbHRhX3tcdGV4dHJte3Rhc2t9fSA9IFxEZWx0YV97XHRleHRybXtkaW19fV57XHRleHRybXtTcGF0aWFsfX0gLSBcRGVsdGFfe1x0ZXh0cm17ZGltfX1ee1x0ZXh0cm17Q29uY2VwdHVhbH19JC4gVGhpcyBkaWZmZXJlbmNlIG9mIGRpZmZlcmVuY2VzIGlzIGEgYml0IG1vcmUgZGlmZmljdWx0IHRvIGludGVycHJldCwgYnV0IHJlY2FsbCB0aGF0ICAkXERlbHRhX3tcdGV4dHJte2RpbX19JCB0ZW5kZWQgdG8gYmUgcG9zaXRpdmUsIHNpbmNlIHBhcnRpY2lwYW50cyBhdHRlbmRlZCBtb3JlIHRvd2FyZHMgdGhlIHZlcnRpY2FsL3N0cmlwZSBmcmVxdWVuY3kgZGltZW5zaW9uIGluIGJvdGggdGFza3MuIFRodXMsICRcRGVsdGFfe1x0ZXh0cm17dGFza319JCBpcyAqcG9zaXRpdmUqIGlmIHBhcnRpY2lwYW50cyB3ZXJlIG1vcmUgYmlhc2VkIHRvd2FyZHMgdGhlIHZlcnRpY2FsL3N0cmlwZSBmcmVxdWVuY3kgZGltZW5zaW9uIGluIHRoZSBzcGF0aWFsIHRhc2suIFZpY2UgdmVyc2EsICRcRGVsdGFfe1x0ZXh0cm17dGFza319JCBpcyAqbmVnYXRpdmUqIGlmIHBhcnRpY2lwYW50cyB3ZXJlIG1vcmUgYmlhc2VkIHRvd2FyZHMgIHRoZSB2ZXJ0aWNhbC9zdHJpcGUgZnJlcXVlbmN5IGRpbWVuc2lvbiBpbiB0aGUgY29uY2VwdHVhbCB0YXNrLiBMZXQncyBub3cgc2VlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiAkXERlbHRhX3tcdGV4dHJte3Rhc2t9fSQgYW5kIGNoYW5nZSBpbiBzY29yZToKYGBge3J9CiNDb21wdXRlIGRlbHRhIHRhc2sKZGlmZkJ5Q29udGV4dCA8LSBkZHBseShkaWZmREYsIH5pZCtlbnZpcm9ubWVudCtGaXJzdFRhc2ssIHBseXI6OnN1bW1hcml6ZSwgcGRpZmYgPSBkaWZmKHBkaWZmKSkgI3N1bW1hcml6ZSBvdXQgY29udGV4dDsgcGRpZmYgc3BhdGlhbCAtIHBkaWZmIGNvbmNlcHR1YWwKI0FkZCBzY29yZSBkaWZmZXJlbmNlCnRhc2twZXJmREYgPC0gZGRwbHkoZGYsIH5pZCtlbnZpcm9ubWVudCtjb250ZXh0K0ZpcnN0VGFzaywgcGx5cjo6c3VtbWFyaXplLCBzY29yZSA9IG1lYW4oeikpICNtZWFuIHNjb3JlIGZvciBlYWNoIHRhc2sKdGFza1BlckRpZmZERiA8LSBkZHBseSh0YXNrcGVyZkRGLCB+aWQrZW52aXJvbm1lbnQsIHBseXI6OnN1bW1hcml6ZSwgc2NvcmVEaWZmID0gZGlmZihzY29yZSkpICNzcGF0aWFsIHNjb3JlICAtIGNvbmNlcHR1YWwgc2NvcmUKZGlmZkJ5Q29udGV4dCRzY29yZURpZmYgPC0gdGFza1BlckRpZmZERiRzY29yZURpZmYgI2FkZCB0byBkYXRhZnJhbWUKCgpwU2NvcmVEaWZmIDwtIGdncGxvdChkaWZmQnlDb250ZXh0LCBhZXMoeCA9IHBkaWZmLCB5ID0gc2NvcmVEaWZmLCBjb2xvciA9IEZpcnN0VGFzaywgZmlsbCA9IEZpcnN0VGFzaykpKyAKICBnZW9tX3BvaW50KGFscGhhID0gMC44KSArIAogICNnZW9tX2xpbmUoYWVzKGdyb3VwPWlkKSwgY29sb3IgPSAnYmxhY2snLCBhbHBoYSA9IDAuMSkrCiAgI2ZhY2V0X2dyaWQofkZpcnN0VGFzaykrCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lPSIiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IiIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKSsKICB4bGFiKGV4cHJlc3Npb24oIERlbHRhW3Rhc2tdKSkrCiAgIHlsYWIoJ1NwYXRpYWwgU2NvcmUgLSBDb25jZXB0dWFsIFNjb3JlJykrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSd0b3AnLCBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKQpwU2NvcmVEaWZmCmBgYApMb29raW5nIGZpcnN0IGF0IHBhcnRpY2lwYW50cyBpbiB0aGUgQ29uY2VwdHVhbCBGaXJzdCBjb25kaXRpb24sIHdlIGZpbmQgYW4gYW5lY2RvdGFsIHJlbGF0aW9uc2hpcCBiZXR3ZWVuICRcRGVsdGFfe1x0ZXh0cm17dGFza319JCBhbmQgZGlmZmVyZW5jZSBpbiBzY29yZSAoJHJfe1x0YXV9PS0uMjAkLCAkcD0uMDE5JCwgJEJGPTIuNCQpLiBUaGUgZGlyZWN0aW9uYWxpdHkgb2YgdGhpcyBlZmZlY3QgaXMgdGhhdCBwYXJ0aWNpcGFudHMgd2l0aCBhIHN0cm9uZ2VyIGJpYXMgdG93YXJkcyB0aGUgdmVydGljYWwvc3RyaXBlIGZyZXF1ZW5jeSBkaW1lbnNpb24gaW4gdGhlIGNvbmNlcHR1YWwgdGFzayB0ZW5kZWQgdG8gaGF2ZSBhIGxvd2VyIHNjb3JlIGluIHRoZSBjb25jZXB0dWFsIHRhc2sgcmVsYXRpdmUgdG8gdGhlIHNwYXRpYWwgdGFzay4gV2UgZmluZCBubyByZWxhdGlvbnNoaXAgYmV0d2VlbiAkXERlbHRhX3tcdGV4dHJte3Rhc2t9fSQgYW5kIGRpZmZlcmVuY2UgaW4gc2NvcmUgZm9yIHRoZSBTcGF0aWFsIEZpcnN0IGNvbmRpdGlvbiAoJHJfe1x0YXV9PS0uMDQkLCAkcD0uNjY2JCwgJEJGPS4xOCQpLiAgQW4gb3V0c3RhbmRpbmcgcXVlc3Rpb24gaXMgd2hldGhlciB0aGlzIHNoaWZ0IGluIGF0dGVudGlvbiBpcyByZXNwb25zaWJsZSBmb3IgdGhlIHRyYW5zZmVyIGVmZmVjdCwgb3IgaXMgbWVyZWx5IGFuIGFydGlmYWN0IG9mIHBhcnRpY2lwYW50cyBiZWluZyBtb3JlIGNhcGFibGUgb2YgbmF2aWdhdGluZyB0aGUgY29uY2VwdHVhbCBkb21haW4gYWZ0ZXIgcHJpb3IgZXhwZXJpZW5jZSB3aXRoIHRoZSBzcGF0aWFsIHRhc2tzLiBXaGlsZSB0aGVzZSBhbmFseXNlcyBwcm92aWRlIGZ1cnRoZXIgY2xhcmlmaWNhdGlvbiBhYm91dCB0aGUgcm9sZSBvZiBhdHRlbnRpb24sIHRoZSBleGFjdCByZWxhdGlvbnNoaXAgYmV0d2VlbiBhdHRlbnRpb24gKGFzIG1lYXN1cmVkIGJ5IGlucHV0IGZyZXF1ZW5jeSkgYW5kIGdlbmVyYWxpemF0aW9uIGlzIHBlcmhhcHMgb3V0c2lkZSB0aGUgc2NvcGUgb2Ygb3VyIGN1cnJlbnQgcGFwZXIuICAKCmBgYHtyIGV2YWw9RiwgZWNobz1UfQpjb3JUZXN0UHJldHR5KHN1YnNldChkaWZmQnlDb250ZXh0LCBGaXJzdFRhc2sgPT0gJ0NvbmNlcHR1YWwgRmlyc3QnKSRwZGlmZiwgc3Vic2V0KGRpZmZCeUNvbnRleHQsIEZpcnN0VGFzayA9PSAnQ29uY2VwdHVhbCBGaXJzdCcpJHNjb3JlRGlmZiwgbWV0aG9kID0gJ2tlbmRhbGwnKQpjb3JUZXN0UHJldHR5KHN1YnNldChkaWZmQnlDb250ZXh0LCBGaXJzdFRhc2sgPT0gJ1NwYXRpYWwgRmlyc3QnKSRwZGlmZiwgc3Vic2V0KGRpZmZCeUNvbnRleHQsIEZpcnN0VGFzayA9PSAnU3BhdGlhbCBGaXJzdCcpJHNjb3JlRGlmZiwgbWV0aG9kID0gJ2tlbmRhbGwnKQpgYGAKCiMjIyBFZmZpY2llbmN5CgpXZSBjYW4gYWxzbyBjb21wdXRlIHRoZSBlZmZpY2llbmN5IG9mIHRoZWlyIHRyYWplY3RvcmllcyBiYXNlZCBvbiAkXHRleHR7ZWZmaWNpZW5jeX0gPSBcZnJhY3tcdGV4dHtNYW5oYXR0YW4gRGlzdGFuY2UgZnJvbSBzdGFydCB0byBzZWxlY3Rpb259fXtcdGV4dHtTdGVwcyB0YWtlbn19JAoKYGBge3J9CmVmZmljZW5jeURGIDwtIGRkcGx5KGRmLCB+aWQrY29udGV4dCwgcGx5cjo6c3VtbWFyaXplLCBlZmZpY2llbmN5ID0gbWVhbihtb3ZlbWVudC9zdGVwcykpCgoKZWZmaWNpZW5jeVBsb3QgPC0gZ2dwbG90KGVmZmljZW5jeURGLCBhZXMoeCA9IGNvbnRleHQsIHkgPSBlZmZpY2llbmN5LCBjb2xvciA9IGNvbnRleHQsIGZpbGwgPSBjb250ZXh0KSkrCiAgZ2VvbV9ib3hwbG90KGZpbGw9TkEsIGNvbG9yID0gJ2JsYWNrJywgd2lkdGggPSAuMiwgb3V0bGllci5zaGFwZSA9IE5BKSsKICBnZW9tX3F1YXNpcmFuZG9tKGFscGhhID0gLjcpKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLGNvbG9yID0gJ2JsYWNrJywgZmlsbD1OQSwgc2hhcGUgPTIzLCBzaXplID0gMyApICsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDIpKSArCiAgeGxhYignJykrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IiIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IiIpICsKICB0aGVtZSggbGVnZW5kLnBvc2l0aW9uPSdub25lJywgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKSsKICB5bGFiKCJFZmZpY2llbmN5IFx1MDBCMVNFIikKZWZmaWNpZW5jeVBsb3QKYGBgClBhcnRpY2lwYW50cyBhcmUgY2xlYXJseSBsZXNzIGVmZmljaWVudCBpbiB0aGUgY29uY2VwdHVhbCB0YXNrIHRoYW4gdGhlIHNwYXRpYWwgdGFzayAoYCR0KDEyOCk9LTIwLjYkLCAkcDwuMDAxJCwgJGQ9MS45JCwgJEJGPjEwMCRgKS4KCmBgYHtyIGV2YWw9RiwgZWNobz1UfQp0dGVzdFByZXR0eShzdWJzZXQoZWZmaWNlbmN5REYsIGNvbnRleHQ9PSdDb25jZXB0dWFsJykkZWZmaWNpZW5jeSwgc3Vic2V0KGVmZmljZW5jeURGLCBjb250ZXh0PT0nU3BhdGlhbCcpJGVmZmljaWVuY3ksIHBhaXJlZD1UKQpgYGAKCk5vdyBsZXQncyBhc2ssIHdoYXQgZmFjdG9ycyBpbmZsdWVuY2UgdHJhamVjdG9yaWVzPyBEbyBsb25nZXIgdHJhamVjdG9yaWVzIG9idGFpbiBoaWdoZXIgcmV3YXJkcz8gWWVzIHRoZXkgZG8gKCRyPS4yMSQsICRwPC4wMDEkLCAkQkY+MTAwJCkuCmBgYHtyfQojc3RlcHMgYXMgYSBmdW5jdGlvbiBvZiBwcmV2aW91cyByZXdhcmQKcFRyYWpMZW5ndGhSZXdhcmQgPC0gZ2dwbG90KHN1YnNldChkZixzdGVwczw9MjApLCBhZXMoeCA9c3RlcHMsICB5ID0geiwgY29sb3IgPSBjb250ZXh0LCBmaWxsID0gY29udGV4dCkpKwogICNnZW9tX3Ntb290aChmaWxsPU5BKSsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKyAKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsIGdlb20gPSAiZXJyb3JiYXIiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW09YygwLDIwKSwgeWxpbT1jKDAsMTAwKSkgKyAjVHVrZXkgb3V0bGllciBjcml0ZXJpb24gaW5kaWNhdGVzIG91dGxpZXJzIGFib3ZlIDIwOyBtaW4oYm94cGxvdC5zdGF0cyhkZiRzdGVwcykkb3V0KQogICNmYWNldF9ncmlkKH5lbnZpcm9ubWVudCkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lPSJUYXNrIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDEsMC4xKSxsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwwKSwgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKSsKICB5bGFiKCJSZXdhcmQgVmFsdWUgwrEgOTUlIENJIikrCiAgeGxhYignVHJhamVjdG9yeSBMZW5ndGgnKQpwVHJhakxlbmd0aFJld2FyZAoKYGBgCgoKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgZW50cm9weSBvZiBlYWNoIHRyYWplY3RvcnkgKGNvbXB1dGVkIG92ZXIgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkaXJlY3Rpb25zIG1vdmVkKS4gSXQgc2VlbXMgbGlrZSBwYXJ0aWNpcGFudHMgaW4gdGhlIGNvbnRleHR1YWwgdGFzayBoYWQgaGlnaGVyIGVudHJvcHkgKGNvbnNpc3RlbnQgd2l0aCBsYXJnZXIgc3RlcCBzaXplcyBhbmQgbG93ZXIgZWZmaWNpZW5jeSksIGFuZCB0aGF0IGxvd2VyIGVudHJvcHkgcHJlZGljdHMgaGlnaGVyIHJld2FyZC4KYGBge3J9CmxpYnJhcnkoZW50cm9weSkKbXllbnQ8LWZ1bmN0aW9uKHgpewogIHJldHVybihlbnRyb3B5LmVtcGlyaWNhbCh0YWJsZSh4KSkpCn0KZGYkdHJhakVudHJvcHkgPC0gc2FwcGx5KGRmJHRyYWplY3RvcmllcywgZnVuY3Rpb24oaSkgICBteWVudChmcm9tSlNPTihhcy5jaGFyYWN0ZXIoaSkpKSkKCmdncGxvdChkZiwgYWVzKHggPSBjb250ZXh0LCB5ID0gdHJhakVudHJvcHksIGZpbGwgPSBjb250ZXh0KSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbixnZW9tPSdiYXInLCBwb3NpdGlvbj0nZG9kZ2UnLCBjb2xvcj0nYmxhY2snKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbSA9ICJlcnJvcmJhciIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkwKSwgd2lkdGggPSAwLjIsIGNvbG9yPSdibGFjaycgKSArCiAgI3NjYWxlX3lfY29udGludW91cyhsYWJlbHM9cGVyY2VudCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiMxQjlFNzciLCAiI0Q5NUYwMiIpLCBuYW1lPSIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMUI5RTc3IiwgIiNEOTVGMDIiKSwgbmFtZT0iIikgKwogIGZhY2V0X2dyaWQofmVudmlyb25tZW50KQogIApnZ3Bsb3Qoc3Vic2V0KGRmLCB0cmFqRW50cm9weT4wKSwgYWVzKHggPSB0cmFqRW50cm9weSwgeSA9IHosIGNvbG9yID0gY29udGV4dCkpKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjA1KSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKSsKICAjc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsgCiAgI3N0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfYm9vdCwgZ2VvbSA9ICJlcnJvcmJhciIpICsKICB4bGFiKCdFbnRyb3B5JykrIHlsYWIoJ1Jld2FyZCBWYWx1ZScpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMUI5RTc3IiwgIiNEOTVGMDIiKSwgbmFtZT0iIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzFCOUU3NyIsICIjRDk1RjAyIiksIG5hbWU9IiIpICsKICBmYWNldF9ncmlkKH5lbnZpcm9ubWVudCkKICAKCmBgYAoKSG93IHdlcmUgYm90aCBkaXN0YW5jZSBhbmQgdHJhamVjdG9yeSBsZW5ndGggaW5mbHVlbmNlZCBieSB0aGUgKnByZXZpb3VzKiByZXdhcmQgdmFsdWU/CmBgYHtyfQojcmV3YXJkIGFuZCBkaXN0YW5jZQojY29yVGVzdFByZXR0eShuYS5vbWl0KGRmKSRkaXN0YW5jZSwgbmEub21pdChkZikkcHJldmlvdXNSZXdhcmQpCnA1IDwtIGdncGxvdChuYS5vbWl0KGRmKSwgYWVzKHg9ZGlzdGFuY2UsIHkgPSBwcmV2aW91c1Jld2FyZCwgY29sb3IgPSBjb250ZXh0LCBmaWxsPWNvbnRleHQpKSArCiAgI2dlb21fY291bnQoYWxwaGE9MC4yLCBzaG93LmxlZ2VuZCA9IEYsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MC4xKSkrCiAgI3NjYWxlX3NpemVfYXJlYShtYXhfc2l6ZSA9IDUpKwogICNnZW9tX2ppdHRlcihhbHBoYT0wLjA1LCBzaXplPTAuNSkrCiAgI2dlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gJ2xpbmUnLCBzaXplPTEpKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb20gPSAncmliYm9uJywgYWxwaGEgPSAwLjcsIGNvbG9yPU5BKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHk9J1ByZXZpb3VzIFJld2FyZCBWYWx1ZScsIHggPSAnRGlzdGFuY2UgQmV0d2VlbiBTZWxlY3Rpb25zJykrCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcyhuID0gNSkpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0iVGFzayIpKwogIHNjYWxlX2ZpbGxfYnJld2VyKCBwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0iVGFzayIpKwogICNjb29yZF9mbGlwKCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMSwxKSwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsMSksIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQua2V5PWVsZW1lbnRfcmVjdChjb2xvcj1OQSksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkKcDUKYGBgCkl0IHNlZW1zIGxpa2UgcGFydGljaXBhbnRzIG1vdmUgZnVydGhlciBhd2F5IGZyb20gdGhlaXIgcHJldmlvdXMgc2VsZWN0aW9uIHdoZW4gdGhlIHJld2FyZCB2YWx1ZSB3YXMgbG93ICgkcj0tLjY2JCwgJHA8LjAwMSQsICRCRj4xMDAkKSwgc3VnZ2VzdGluZyBiYXNpYyBldmlkZW5jZSBvZiBnZW5lcmFsaXphdGlvbiBiZWhhdmlvci4KCkxldCdzIHJ1biBhIG1peGVkIG1vZGVsIG9uIHRoZXNlIHJlc3VsdHMKCmBgYHtyfQojTWl4ZWQgZWZmZWN0cyBtb2RlbGluZwojUHJldmlvdXMgcmV3YXJkIHZhbHVlIGFuZCBkaXN0YW5jZSBiZXR3ZWVuIHNlbGVjdGlvbnMKcHJpb3IgPC0gYyhzZXRfcHJpb3IoIm5vcm1hbCgwLDEpIiwgY2xhc3MgPSAiYiIpLHNldF9wcmlvcigibm9ybWFsKDAsMSkiLCBjbGFzcyA9ICJzZCIpKQpkaXN0YW5jZVJld2FyZE1NIDwtIHJ1bl9tb2RlbChicm0oZGlzdGFuY2UgfiAwKyBpbnRlcmNlcHQrIHByZXZpb3VzUmV3YXJkK2NvbnRleHQrcHJldmlvdXNSZXdhcmQqY29udGV4dCArKDErcHJldmlvdXNSZXdhcmQqY29udGV4dHxpZCksIGRhdGE9c3Vic2V0KGRmLCAhaXMubmEoZGYkZGlzdGFuY2UpKSwgcHJpb3IgPSBwcmlvcixjb3Jlcz00LCAgaXRlciA9IDQwMDAsIHdhcm11cCA9IDEwMDAsIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45OSkpLCBtb2RlbE5hbWUgPSAnZGlzdGFuY2VSZXdhcmRNTScpCiN0YWJfbW9kZWwoZGlzdGFuY2VSZXdhcmRNTSkgI1JlYWxseSBzbG93IQpmaXhlZFRlcm1zIDwtIGZpeGVmKGRpc3RhbmNlUmV3YXJkTU0pI0xvb2sgYXQgZml4ZWQgdGVybXMKCiNOb3cgZ2VuZXJhdGUgcHJlZGljdGlvbnMsIHJlbW92aW5nIGlkIGFzIGEgcmFuZG9tIGVmZmVjdAp4c2VxIDwtIHNlcSgwLDEwMCkKbmV3ZGF0IDwtZGF0YS5mcmFtZShjb250ZXh0ID0gcmVwKGMoIkNvbmNlcHR1YWwiLCJTcGF0aWFsIiksIGVhY2g9MTAxKSwgcHJldmlvdXNSZXdhcmQgPSByZXAoeHNlcSwyKSkKcHJlZHMgPC0gZml0dGVkKGRpc3RhbmNlUmV3YXJkTU0sIHJlX2Zvcm11bGEgPSBOQSwgbmV3ZGF0YSA9IG5ld2RhdCwgcHJvYnMgPSBjKDAuMDI1LCAwLjk3NSkpCiNjcmVhdGUgbmV3IGZpeGVkIGVmZmVjdHMgZGF0YWZyYW1lCmZpeGVkREYgPC0gZGF0YS5mcmFtZShjb250ZXh0ID0gcmVwKGMoIkNvbmNlcHR1YWwiLCJTcGF0aWFsIiksIGVhY2g9MTAxKSwgcHJldmlvdXNSZXdhcmQgPSByZXAoeHNlcSwyKSwKICAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gcHJlZHNbLDFdLCBsb3dlciA9IHByZWRzWywzXSwgdXBwZXIgPSBwcmVkc1ssNF0gKQoKcDVhbHQgPC0gZ2dwbG90KHN1YnNldChkZiwgIWlzLm5hKGRmJGRpc3RhbmNlKSksIGFlcyhwcmV2aW91c1Jld2FyZCwgZGlzdGFuY2UsIGNvbG9yID0gY29udGV4dCwgZmlsbCAgPSBjb250ZXh0KSkgKwogICNnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKHJhbmRvbURpc3RhbmNlREYkZGlzdGFuY2UsIG5hLnJtPVQgKSwgc2l6ZSA9IDEsIGNvbG9yID0gJ2JsYWNrJywgbGluZXR5cGU9J2Rhc2hlZCcpKyAKICBnZW9tX2xpbmUoZGF0YSA9IGZpeGVkREYsICBzaXplID0gMSkrICNHUCBpcwogIGdlb21fcmliYm9uKGRhdGEgPSBmaXhlZERGLCBhZXMoeW1pbj1sb3dlciwgeW1heCA9IHVwcGVyKSwgY29sb3IgPSBOQSwgYWxwaGEgPSAwLjQgKSsKICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbixnZW9tPSdwb2ludCcsIGFscGhhID0gMC44KSsKICAjZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSsKICAjY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMTAwKSkrCiAgeGxpbShjKDAsMTAwKSkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0iVGFzayIpKwogIHNjYWxlX2ZpbGxfYnJld2VyKCBwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0iVGFzayIpKwogICNmYWNldF9ncmlkKH5jb250ZXh0LCBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKGNvbnRleHRMYWJlbHMpICkrCiAgeGxhYigiUHJldmlvdXMgUmV3YXJkIFZhbHVlIikrCiAgeWxhYigiRGlzdGFuY2UgQmV0d2VlbiBTZWxlY3Rpb25zIikrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gNTAsIHkgPSA4LCBsYWJlbCA9ICJwYXN0ZShpdGFsaWMoYilbcHJldlJld2FyZF0gLCBcIiA9IC0wLjA2LCA5NSUgSFBEOiBbLTAuMDYsIC0wLjA2XVwiKSIsIHBhcnNlID0gVFJVRSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMCwgMCksIGxlZ2VuZC5qdXN0aWZpY2F0aW9uPWMoMCwwKSwgc3RyaXAuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5rZXk9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkpCnA1YWx0CgpgYGAKCkF0IHRoZXIgc2FtZSB0aW1lLCBwYXJ0aWNpcGFudHMgYWxzbyBtb3ZlZCBmdXRoZXIgYXdheSBmcm9tIHRoZWlyIGluaXRpYWwgc3RhcnRpbmcgcG9pbnQgYWZ0ZXIgb2JzZXJ2aW5nIGxhcmdlciByZXdhcmQgdmFsdWVzIChgciBjb3JUZXN0UHJldHR5KG5hLm9taXQoZGYpJG1vdmVtZW50LCBuYS5vbWl0KGRmKSRwcmV2aW91c1Jld2FyZCwgbWV0aG9kPSdrZW5kYWxsJylgKS4gTm90ZSB0aGF0IHRoZSB0aGVyZSB3YXMgYSByYW5kb20gc3RhcnRpbmcgcG9zaXRpb24gYXQgdGhlIGJlZ2lubmluZyBvZiBlYWNoIHRyaWFsLiBTbyB0aGUgc3RhcnRpbmcgcG9pbnQgaXMgbm90IHRoZSBzYW1lIGFzIHRoZSBwcmV2aW91cyBzZWxlY3Rpb24uIEEgc21hbGwgZGlzdGFuY2UgZnJvbSB0aGUgaW5pdGlhbCBzdGFydGluZyBwb2ludCBpcyBpbmRpY2F0aXZlIG9mIHJhbmRvbSBzZWFyY2ggYmVoYXZpb3IsIHV0aWxpemluZyB0aGUgcmFuZG9tbmVzcyBvZiB0aGUgaW5pdGlhbGl6YXRpb24uIFRoZSB0cmVuZCBpbmRpY2F0ZXMgdGhhdCBwYXJ0aWNpcGFudHMgbWFkZSBhIGxhcmdlciBlZmZvcnQgdG8gc2VhcmNoIGluIGEgZGlyZWN0ZWQgZmFzaGlvbiBhZnRlciBvYnNlcnZpbmcgbGFyZ2UgcmV3YXJkIHZhbHVlcwoKYGBge3J9CgpwcmlvciA8LSBjKHNldF9wcmlvcigibm9ybWFsKDAsMSkiLCBjbGFzcyA9ICJiIiksc2V0X3ByaW9yKCJub3JtYWwoMCwxKSIsIGNsYXNzID0gInNkIikpCmRpc3RhbmNlSW5pdGlhbE1NIDwtIHJ1bl9tb2RlbChicm0obW92ZW1lbnQgfjAgKyBpbnRlcmNlcHQgK3ByZXZpb3VzUmV3YXJkKmNvbnRleHQgKygxK3ByZXZpb3VzUmV3YXJkKmNvbnRleHxpZCksIGRhdGE9c3Vic2V0KGRmLCAhaXMubmEoZGYkbW92ZW1lbnQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3Jlcz00LCAgaXRlciA9IDQwMDAsIHdhcm11cCA9IDEwMDAsIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhID0gMC45OSkpLCBtb2RlbE5hbWUgPSAnZGlzdGFuY2VJbml0aWFsTU0nKQojYmF5ZXNfUjIoZGlzdGFuY2VJbml0aWFsTU0pCiN0YWJfbW9kZWwoZGlzdGFuY2VJbml0aWFsTU0pCmZpeGVkVGVybXMgPC0gZml4ZWYoZGlzdGFuY2VJbml0aWFsTU0pI0xvb2sgYXQgZml4ZWQgdGVybXMKCiNOb3cgZ2VuZXJhdGUgcHJlZGljdGlvbnMsIHJlbW92aW5nIGlkIGFzIGEgcmFuZG9tIGVmZmVjdAp4c2VxIDwtIHNlcSgxLDEwMCkKbmV3ZGF0IDwtZGF0YS5mcmFtZShjb250ZXh0ID0gcmVwKGMoIkNvbmNlcHR1YWwiLCJTcGF0aWFsIiksIGVhY2g9MTAwKSwgcHJldmlvdXNSZXdhcmQgPSByZXAoeHNlcSwyKSkKcHJlZHMgPC0gZml0dGVkKGRpc3RhbmNlSW5pdGlhbE1NLCByZV9mb3JtdWxhID0gTkEsIG5ld2RhdGEgPSBuZXdkYXQsIHByb2JzID0gYygwLjAyNSwgMC45NzUpKQojY3JlYXRlIG5ldyBmaXhlZCBlZmZlY3RzIGRhdGFmcmFtZQpmaXhlZERGIDwtIGRhdGEuZnJhbWUoY29udGV4dCA9IHJlcChjKCJDb25jZXB0dWFsIiwiU3BhdGlhbCIpLCBlYWNoPTEwMCksIHByZXZpb3VzUmV3YXJkID0gcmVwKHhzZXEsMiksCiAgICAgICAgICAgICAgICAgICAgICBtb3ZlbWVudCA9IHByZWRzWywxXSwgbG93ZXIgPSBwcmVkc1ssM10sIHVwcGVyID0gcHJlZHNbLDRdICkKCnA2IDwtIGdncGxvdChzdWJzZXQoZGYsICFpcy5uYShkZiRtb3ZlbWVudCkpLCBhZXMocHJldmlvdXNSZXdhcmQsIG1vdmVtZW50LCBjb2xvciA9IGNvbnRleHQsIGZpbGwgID0gY29udGV4dCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKHJhbmRvbURpc3RhbmNlREYkZGlzdGFuY2UsIG5hLnJtPVQgKSwgc2l6ZSA9IDEsIGNvbG9yID0gJ2JsYWNrJywgbGluZXR5cGU9J2Rhc2hlZCcpKyAKICBnZW9tX2xpbmUoZGF0YSA9IGZpeGVkREYsICBzaXplID0gMSkrICNHUCBpcwogIGdlb21fcmliYm9uKGRhdGEgPSBmaXhlZERGLCBhZXMoeW1pbj1sb3dlciwgeW1heCA9IHVwcGVyKSwgY29sb3IgPSBOQSwgYWxwaGEgPSAwLjQgKSsKICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbixnZW9tPSdwb2ludCcsIGFscGhhID0gMC44KSsKICAjZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBsaW5ldHlwZSA9ICdkYXNoZWQnKSsKICAjY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMTAwKSkrCiAgeGxpbShjKDAsMTAwKSkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0iVGFzayIpKwogIHNjYWxlX2ZpbGxfYnJld2VyKCBwYWxldHRlID0gJ0RhcmsyJywgbmFtZT0iVGFzayIpKwogICNmYWNldF9ncmlkKH5jb250ZXh0LCBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKGNvbnRleHRMYWJlbHMpICkrCiAgeGxhYigiUHJldmlvdXMgUmV3YXJkIFZhbHVlIikrCiAgeWxhYigiRGlzdGFuY2UgRnJvbSBJbml0aWFsIFBvc2l0aW9uIikrCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gNTAsIHkgPSA4LCBsYWJlbCA9ICJwYXN0ZShpdGFsaWMoYilbcHJldlJld2FyZF0gLCBcIiA9IDAuMDEsIDk1JSBIUEQ6IFswLjAxLCAwLjAxXVwiKSIsIHBhcnNlID0gVFJVRSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPWMoMCwgMC43KSwgbGVnZW5kLmp1c3RpZmljYXRpb249YygwLDEpLCBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkKcDYKYGBgCgoKIyMgSGVhdG1hcCBvZiBjbGlja3MKCkxldCdzIGxvb2sgYXQgYW55IHBhdHRlcm5zIGluIGhvdyBwZW9wbGUgc2VhcmNoZWQgdGhlIGlucHV0IHNwYWNlLiBVbnN1cnByaXNpbmdseSwgdGhlcmUgaXMgYSBwcmVmZXJlbmNlIGZvciBjb3JuZXJzIGFuZCBlZGdlcy4gWWVsbG93IGlzIG1hcHBlZCB0byByYW5kb20gY2hhbmNlLCBzbyBvcmFuZ2UgYW5kIHJlZCBhcmUgaGlnaGVyIHRoYW4gY2hhbmNlLCB3aGlsZSBncmVlbiBhbmQgYmx1ZSBhcmUgbG93ZXIgdGhhbiBjaGFuY2UuCgpgYGB7cn0KI0hlYXRtYXAgb2YgY2xpY2tzCiNzcGF0aWFsIGFuZCBzcGF0aWFsCnNwYXRpYWxDb3VudHMgPC0gZGRwbHkoc3Vic2V0KGRmLCBjb250ZXh0ID09ICdTcGF0aWFsJyksIC4oeCwgeSksIG5yb3cpCm5hbWVzKHNwYXRpYWxDb3VudHMpIDwtIGMoIlgiLCAiWSIsICJGcmVxIikKc3BhdGlhbENvdW50cyRQcm9iIDwtIHNwYXRpYWxDb3VudHMkRnJlcSAvIHN1bShzcGF0aWFsQ291bnRzJEZyZXEpCgpjb25jZXB0Q291bnRzIDwtIGRkcGx5KHN1YnNldChkZiwgY29udGV4dCA9PSAnQ29uY2VwdHVhbCcpLCAuKHgsIHkpLCBucm93KQpuYW1lcyhjb25jZXB0Q291bnRzKSA8LSBjKCJYIiwgIlkiLCAiRnJlcSIpCmNvbmNlcHRDb3VudHMkUHJvYiA8LSBjb25jZXB0Q291bnRzJEZyZXEgLyBzdW0oY29uY2VwdENvdW50cyRGcmVxKQoKbWF4RnJlcSA8LSBtYXgobWF4KHNwYXRpYWxDb3VudHMkUHJvYiksIG1heChjb25jZXB0Q291bnRzJFByb2IpKQoKaGVhdG1hcFNwYXRpYWwgPC0gZ2dwbG90KHNwYXRpYWxDb3VudHMsIGFlcyh4PVgsIHkgPSBZLCBmaWxsPVByb2IpKSArCiAgZ2VvbV90aWxlKCkrCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIsIG5hbWUgPSAnRnJlcScsIHZhbHVlcz1yZXNjYWxlKGMoMCwxLzY0LG1heEZyZXEpKSxsaW1pdHMgPSBjKDAsbWF4RnJlcSksbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSsKICB0aGVtZV9jbGFzc2ljKCkgKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQua2V5PWVsZW1lbnRfcmVjdChjb2xvcj1OQSksIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSxheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkscGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSxwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSxwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpKSsKICBnZ3RpdGxlKCdTcGF0aWFsIEhlYXRtYXAnKQpoZWF0bWFwU3BhdGlhbAoKY29uY2VwdHVhbEhlYXRtYXAgPC0gZ2dwbG90KGNvbmNlcHRDb3VudHMsIGFlcyh4PVgsIHkgPSBZLCBmaWxsPVByb2IpKSArCiAgZ2VvbV90aWxlKCkrCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIsbmFtZSA9ICdGcmVxJywgdmFsdWVzPXJlc2NhbGUoYygwLDEvNjQsbWF4RnJlcSkpLCBsaW1pdHMgPSBjKDAsbWF4RnJlcSksbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHhsYWIoJ1JvdGF0aW9uJykrCiAgeWxhYignU3RyaXBlcycpKwogIGNvb3JkX2VxdWFsKCkgKwogIHRoZW1lKHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQua2V5PWVsZW1lbnRfcmVjdChjb2xvcj1OQSksIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSxheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCkscGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSxwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSxwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpKSsKICBnZ3RpdGxlKCdDb25jZXB0dWFsIEhlYXRtYXAnKQpjb25jZXB0dWFsSGVhdG1hcAoKYGBgCgojIyBSZWFjdGlvbiB0aW1lcwoKV2UgY2FuIGFsc28gYW5hbHl6ZSBwYXJ0aWNpcGFudCByZWFjdGlvbiB0aW1lcy4gUGFydGljaXBhbnRzIHdlcmUgc2xvd2VyIGluIHRoZSBjb25jZXB0dWFsIHRhc2sgKGByIHRmREYgPC0gZGRwbHkoZGYsIH5pZCtjb250ZXh0K2Vudmlyb25tZW50LCBwbHlyOjpzdW1tYXJpemUsIHRzID0gbWVhbih0cykpCnR0ZXN0UHJldHR5KGxvZyhzdWJzZXQodGZERiwgY29udGV4dCA9PSAnQ29uY2VwdHVhbCcpJHRzKSwgbG9nKHN1YnNldCh0ZkRGLCBjb250ZXh0ID09ICdTcGF0aWFsJykkdHMpLCBwYWlyZWQ9VClgKSwgYnV0IHRoZXJlIHdlcmUgbm8gZGlmZmVyZW5jZXMgYWNyb3NzIGVudmlyb25tZW50cyAoYHIgdGZERiA8LSBkZHBseShkZiwgfmlkK2NvbnRleHQrZW52aXJvbm1lbnQsIHBseXI6OnN1bW1hcml6ZSwgdHMgPSBtZWFuKHRzKSkKdHRlc3RQcmV0dHkobG9nKHN1YnNldCh0ZkRGLCBlbnZpcm9ubWVudCA9PSAnU21vb3RoJykkdHMpLCBsb2coc3Vic2V0KHRmREYsIGVudmlyb25tZW50ID09ICdSb3VnaCcpJHRzKSlgKS4KCgoKYGBge3J9CiNJbmRpdmlkdWFsIHBhcnRpY2lwYW50IHF1YXJ0aWxlIHNwbGl0cwpkZiRwcmV2UmV3YXJkVmFsdWUgPC0gTkEKZm9yIChwaWQgaW4gdW5pcXVlKGRmJGlkKSl7CiAgc3ViZCA8LSBzdWJzZXQoZGYsIGlkPT1waWQpCiAgeHMgPC0gcXVhbnRpbGUoc3ViZCRwcmV2aW91c1Jld2FyZCwgcHJvYnM9MDo0LzQsIG5hLnJtID0gVCkKICBkZltkZiRpZD09cGlkLCdwcmV2UmV3YXJkVmFsdWUnXSA8LSBjdXQoc3ViZCRwcmV2aW91c1Jld2FyZCwgYnJlYWtzPXhzLGxhYmVscz1jKCJRMSIsICJRMiIsICJRMyIsICJRNCIpICkKfQoKZGYkcHJldlJld2FyZFZhbHVlIDwtIGZhY3RvcihkZiRwcmV2UmV3YXJkVmFsdWUpCmxldmVscyhkZiRwcmV2UmV3YXJkVmFsdWUpIDwtIGMoIlExIiwgIlEyIiwgIlEzIiwgIlE0IikKY29sZnVuYzwtY29sb3JSYW1wUGFsZXR0ZShjKCIjMEQwODg3RkYiLCAiI0NDNDY3OEZGIiwgIiNGMEY5MjFGRiIpKQpwMTEgPC0gZ2dwbG90KHN1YnNldChkZiwgdHM+MCAmICFpcy5uYShwcmV2UmV3YXJkVmFsdWUpKSwgYWVzKHg9dHMvMTAwMCwgeT1wcmV2UmV3YXJkVmFsdWUsIGZpbGwgPSBwcmV2UmV3YXJkVmFsdWUpKSsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKCkrCiAgeGxhYignUlQgaW4gc2Vjb25kcyAobG9nIHNjYWxlKScpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xmdW5jKDUpLCBuYW1lPSIiKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xmdW5jKDUpLCBuYW1lPSIiKSsKICBzY2FsZV94X2xvZzEwKCkrCiAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzaWRlcz0nYicpKwogIGZhY2V0X2dyaWQofmNvbnRleHQsIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoY29udGV4dExhYmVscykpKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLjEsNTApKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBjKDAuMDEsIDApKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnLCBzdHJpcC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLmtleT1lbGVtZW50X3JlY3QoY29sb3I9TkEpKSsKICB5bGFiKCdQcmV2aW91cyBSZXdhcmQnKQpwMTEKYGBgCgpUaGVyZSBkb2Vzbid0IHNlZW0gdG8gYmUgYW55IGNvbm5lY3Rpb24gYmV0d2VlbiByZWFjdGlvbiB0aW1lIGFuZCBwcmV2aW91cyByZXdhcmQgdmFsdWUuIEl0IHNlZW1zIGxpa2UgYW55IGluZmx1ZW5jZSBvZiBkZWxpYmVyYXRpb24gb24gcmVhY3Rpb24gdGltZSBpcyBsaWtlbHkgd2FzaGVkIG91dCBieSBsYXJnZXIgaW5mbHVlbmNlIG9mIHRyYWplY3RvcnkgbGVuZ3RoLgoKYGBge3J9CmdncGxvdChzdWJzZXQoZGYsc3RlcHM8PTIwKSwgYWVzKHggPXN0ZXBzLCAgeSA9IGxvZyh0cy8xMDAwKSwgY29sb3IgPSBjb250ZXh0LCBmaWxsID0gY29udGV4dCkpKwogICNnZW9tX3Ntb290aChmaWxsPU5BKSsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKyAKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX2Jvb3QsIGdlb20gPSAiZXJyb3JiYXIiKSArCiAgI2Nvb3JkX2NhcnRlc2lhbih4bGltPWMoMCwyMCksIHlsaW09Yyg0LDEwKSkgKyAjVHVrZXkgb3V0bGllciBjcml0ZXJpb24gaW5kaWNhdGVzIG91dGxpZXJzIGFib3ZlIDIwOyBtaW4oYm94cGxvdC5zdGF0cyhkZiRzdGVwcykkb3V0KQogICNmYWNldF9ncmlkKH5lbnZpcm9ubWVudCkrCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIG5hbWU9IlRhc2siKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBuYW1lPSJUYXNrIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj1jKDAuMDUsMSksbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsMSksIHN0cmlwLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5rZXk9ZWxlbWVudF9yZWN0KGNvbG9yPU5BKSkrCiAgeWxhYigiUlQgaW4gc2Vjb25kcyAobG9nIHNjYWxlKSIpKwogIHhsYWIoJ1RyYWplY3RvcnkgTGVuZ3RoJykrCiAgc2NhbGVfeV9sb2cxMCgpKwogIGFubm90YXRpb25fbG9ndGlja3Moc2lkZXM9J2wnKQoKYGBgCgojIEZpbmFsIFBsb3RzCiMjIE1haW4gdGV4dAoKYGBge3IgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDl9CiNjb21wbGV0ZXBsb3QgPC0gcGxvdF9ncmlkKHAzYSwgcDFiLCBwNGFsdCwgdHJhamVjdG9yeXBsb3QsIHBHZW5lcmFsaXphdGlvbiwgcDUsY29uY2VwdHVhbEhlYXRtYXAsIGhlYXRtYXBTcGF0aWFsICwgbmNvbD0yLCBsYWJlbHMgPSAiYXV0byIpCmNvbXBsZXRlcGxvdCA8LSBjb3dwbG90OjpwbG90X2dyaWQocDFhLCBwMWIsIHBPcmRlciAscDNhLCAgcDRhbHQsIHA1YWx0LCBuY29sPTIsIGxhYmVscyA9ICJhdXRvIikKY29tcGxldGVwbG90CgpnZ3NhdmUoJy4uL3Bsb3RzL2JlaGF2aW9yYWxwbG90LnBkZicsY29tcGxldGVwbG90LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCB1bml0PSdpbicsIHVzZURpbmdiYXRzPUYpCmBgYAojIyBTSQoKYGBge3IgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA0fQoKI1NJIHBsb3RzCnRyYWluaW5nUm91bmQgPC0gY293cGxvdDo6cGxvdF9ncmlkKHRyYWpDb21wbGV0ZSwgdHJhanAxYSwgdHJhamhlYXRtYXAsIHBFcnJvciwgIG5jb2w9MiwgbGFiZWxzID0gJ2F1dG8nKQp0cmFpbmluZ1JvdW5kCmdnc2F2ZShmaWxlbmFtZSA9ICcuLi9wbG90cy9UcmFpbmluZ1Bsb3RzLnBkZicsIHRyYWluaW5nUm91bmQsIHdpZHRoID0gOSxoZWlnaHQgPSA2LCB1bml0cyA9ICdpbicsIHVzZURpbmdiYXRzPUZBTFNFKQoKCmBgYAoKYGBge3IgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA0fQp0cmFqZWN0b3J5UGxvdHMgPC0gY293cGxvdDo6cGxvdF9ncmlkKHRyYWplY3RvcnlwbG90LHBUcmFqTGVuZ3RoUmV3YXJkLHA2LCBpbnB1dGRpcixwQXR0ZW50aW9uVGFza09yZGVyLCBwU2NvcmVBdHRlbnRpb24sICBuY29sPTMsIGxhYmVscz0iYXV0byIpCnRyYWplY3RvcnlQbG90cwpnZ3NhdmUoZmlsZW5hbWUgPSAnLi4vcGxvdHMvVHJhamVjdG9yeVBsb3RzLnBkZicsIHRyYWplY3RvcnlQbG90cywgd2lkdGggPSAxMixoZWlnaHQgPSA2LCB1bml0cyA9ICdpbicsIHVzZURpbmdiYXRzPUZBTFNFKQoKCmBgYAoKYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDR9CgpoZWF0bWFwcyA8LSBjb3dwbG90OjpwbG90X2dyaWQoY29uY2VwdHVhbEhlYXRtYXAsIGhlYXRtYXBTcGF0aWFsLCBsYWJlbHMgPSAiYXV0byIpCmhlYXRtYXBzCmdnc2F2ZShmaWxlbmFtZSA9ICcuLi9wbG90cy9oZWF0bWFwcy5wZGYnLCBoZWF0bWFwcywgd2lkdGggPSA4LGhlaWdodCA9IDQsIHVuaXRzID0gJ2luJywgdXNlRGluZ2JhdHM9RkFMU0UpCmBgYAoK